对python来说非常陌生,它试图创建一个游戏,在这个游戏中可以创建任意数量的军队,但是每个军队都会预先呈现士兵的名字。
我想我需要使用super init来真正减少重复的代码,但是我一生都不知道如何使它工作据我所知,我的类Army
应该是父类,其中RedArmy
和Scout
是子类。我只是在努力理解super().__init__()
应该在哪里?
class Army:
def __init__(self):
self.color = None
self.scoutname = None
self.demomanname = None
self.medicname = None
def train_scout(self, weapon):
return Scout(self.color, self.scoutname, weapon)
class RedArmy(Army):
def __init__(self):
self.color = "Red"
self.scoutname = "Yankee"
self.demomanname = "Irish"
self.medicname = "Dutch"
class BlueArmy(Army):
pass
class Scout:
specialization = "fast captures"
def __init__(self, color, scoutname, weapon):
self.color = color
self.scoutname = scoutname
self.weapon = weapon
def introduce(self):
return (f'Hi I\'m {self.scoutname}, I do {self.specialization} and I wield a {self.weapon}')
my_army = RedArmy()
soldier_1 = my_army.train_scout("baseball bat")
print(soldier_1.introduce())
最佳答案
在哪里放置super().__init__
(如果有)取决于类层次结构的具体情况。
最常见的情况是,如果你把它放在哪里很重要,你需要它在子类的__init__
方法的一开始这将确保所有基类变量都已设置,其所有不变量都已满足,并且其所有方法都可以由子类__init__
代码的其余部分调用。
在您的例子中,这很重要,因为您在基类和子类中设置了相同的属性。显然,您希望子类版本是采用的版本,因此它必须在默认分配之后,而不是之前:
class RedArmy(Army):
def __init__(self):
super().__init__()
self.color = "Red"
self.scoutname = "Yankee"
self.demomanname = "Irish"
self.medicname = "Dutch"
然而,值得考虑的是,您是否真的希望基类首先将这些变量设置为
None
。我假设在您的实际代码中,
BlueArmy
不只是要pass
,而是要做与RedArmy
相同的事情,用一些字符串替换所有这些值。另外,代码的其余部分可能假定那里有有效的字符串,而不是
None
。像TypeError: '<' not supported between instances of 'NoneType' and 'str'
这样的异常比AttributeError: 'GreenArmy' object has no attribute 'scoutname'
更难调试,也不容易调试,所以为什么不干脆不使用默认值呢?然后,您可以完全消除Army.__init__
,并且您不必首先担心在子类初始值设定项中调用super
。或者,您可以让
Army.__init__
获取用于赋值的参数,并让子类调用super().__init__("Red", "Yankee", "Irish", "Dutch")
。然后,Army()
将引发一个TypeError
而不是创建一个无效的Army
实例或者您可以创建一个名为@abstractmethod
的self._setup()
调用并期望每个子类提供,因此Army.__init__
将引发一个关于实例化抽象类的更有意义的Army()
。这些改进使得调试TypeError
子类变得更加容易,如果您只有其中的两个子类,它们可能只是浪费时间,但是如果您有一堆子类,这些子类将由不同的人开发,或者经过很长的时间,可能是值得的。