代码之家  ›  专栏  ›  技术社区  ›  yourleftleg

正在与类继承和super()斗争。\u init__

  •  3
  • yourleftleg  · 技术社区  · 6 年前

    对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())
    
    2 回复  |  直到 6 年前
        1
  •  5
  •   abarnert    6 年前

    放在哪里 super().__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 ,将所有这些值替换为一些字符串。

    另外,代码的其余部分可能会假设那里有有效的字符串,而不是 是的。像这样的例外 TypeError: '<' not supported between instances of 'NoneType' and 'str' 调试起来比 AttributeError: 'GreenArmy' object has no attribute 'scoutname' ,不容易,那为什么不把违约排除在外呢?然后你就可以消除 Army.__init__ 完全可以,你不用担心打电话来 super 在子类初始化器中。

    或者,你可以 军队。__ 获取用于赋值的参数,并让子类调用 super().__init__("Red", "Yankee", "Irish", "Dutch") 是的。那么, Army() 会引起 TypeError 而不是创建一个无效的 Army 实例。或者你可以做一个 @abstractmethod 命名的 self._setup() 那个 军队。__ 调用并期望每个子类提供 陆军() 将培养出更有意义的 类型错误 关于实例化抽象类。这些改进使调试 军队 子类——如果你只有其中的两个,那可能只是浪费时间,但是如果你有一堆子类,这些子类将由不同的人开发,或者经过很长一段时间,这可能是值得的。

        2
  •  -1
  •   Brian Rodriguez    6 年前

    如果您希望您的类利用 super init 以下内容:

    class Army:    
        def __init__(self, color=None, scoutname=None, demomanname=None,
                     medicname=None):
            self.color = color
            self.scoutname = scoutname
            self.demomanname = demomanname
            self.medicname = medicname
    
        def train_scout(self, weapon):
            return Scout(self.color, self.scoutname, weapon)
    
    
    class RedArmy(Army):
        def __init__(self, color="Red", scoutname="Yankee", demomanname="Irish",
                     medicname="Dutch"):
            super().__init__(color, scoutname, demomanname, medicname)
    
    
    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 '
                f'a {self.weapon}')
    
    
    my_army = RedArmy()    
    soldier_1 = my_army.train_scout("baseball bat")
    print(soldier_1.introduce())