简体   繁体   English

在 Python 中使用 super() 的多个 inheritance

[英]Multiple inheritance with super() in Python

I am practicing multiple inheritances in Python.我在 Python 中练习多重继承。 Without the Boss class, everything goes well.没有Boss class,一切顺利。 Any help is highly appreciated.非常感谢任何帮助。 I've referred to: How does Python's super() work with multiple inheritance?我提到过: Python 的 super() 如何与多个 inheritance 一起工作?

The feedback:反馈:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
 in 
 41 print(archer1.__str__())
 42 print('')
---> 43 boss = Boss("Boss", 50, 50, 100)
 44 print(boss.__str__())

 in __init__(self, name, power, agility, HP)
 27 class Boss(Worrior,Archer):
 28      def __init__(self, name, power, agility, HP):
---> 29      Worrior.__init__(self, name, power, HP)
 30          Archer.__init__(self, name, agility, HP)
 31      def __str__(self):

 in __init__(self, name, power, HP)
  7 class Worrior(Player):
  8     def __init__(self, name, power, HP):
----> 9     super().__init__(HP)
 10         self.name = name
 11         self.power = power

TypeError: __init__() missing 2 required positional arguments: 'agility' and 'HP'

It seems after taking the power attribute inside the Worrior class, and then stop.好像取了Worrior class里面的power属性,然后停了。

class Player:
def __init__(self,HP):
    self.HP = HP 
def sign_in(self):
    print('player sign in')
# put the class want to extend from

class Worrior(Player):
def __init__(self, name, power, HP):
    super().__init__(HP)
    self.name = name
    self.power = power
# it's the toString() method in java
# need to override the dunder(magic) method
def __str__(self):
    return "The worrior's name: " f'{self.name} \n' \
        "He has the power:" f'{self.power}'

class Archer(Player):
def __init__(self, name, agility, HP):
    super().__init__(HP)
    self.name = name
    self.agility = agility
def __str__(self):
    return "The archer's name: " f'{self.name} \n' \
        "He has the agility:" f'{self.agility}'

class Boss(Worrior,Archer):
def __init__(self, name, power, agility, HP):
     Worrior.__init__(self, name, power, HP)
     Archer.__init__(self, name, agility, HP)
def __str__(self):
    return "The boss's name: " f'{self.name} \n' \
        "With Worrior's power " f'{self.power} \n' \
        "and With Archer's agilit" f'{self.agility}'\
        "The boss' HP is: " f'{self.HP}'
boss = Boss("Boss", 50, 50, 100)
print(boss.__str__())

The link from @Thierry Lathuille is the correct one to read, but I'll try to add some extra explanation. @Thierry Lathuille 的链接是正确的阅读链接,但我会尝试添加一些额外的解释。 The MRO for the initializer is [Boss, Worrior, Archer, Player].初始化器的 MRO 是 [Boss, Worrior, Archer, Player]。 What this means (somewhat confusingly) is that when Worrior calls super(), this is actually referring to Archer, not Player.这意味着(有点令人困惑)是当 Worrior 调用 super() 时,这实际上是指 Archer,而不是 Player。 If you place print(super().__init__) before each time you call the method, you will find output like this prior to your crash:如果您在每次调用该方法之前放置print(super().__init__) ,您会在崩溃之前找到 output :

<bound method Worrior.__init__ of <__main__.Boss object at 0x10af5f780>>
<bound method Archer.__init__ of <__main__.Boss object at 0x10af5f780>>
Traceback (most recent call last):
...

This is the major pitfall IMHO with multiple inheritance in Python, and I generally advise against it unless you have zero-argument initializers.恕我直言,这是在 Python 中有多个 inheritance 的主要陷阱,除非您有零参数初始化程序,否则我通常建议不要这样做。

If you try to explicitly call each base class initializer (eg Player.__init__ ), then you will end up with some of your initializers executing multiple times.如果您尝试显式调用每个基本 class 初始化程序(例如Player.__init__ ),那么最终您的一些初始化程序会执行多次。

In order to be able to pass your arguments through, you'll need to leverage **kwargs.为了能够通过您的 arguments,您需要利用 **kwargs。 Additionally, as these get passed through, each unique argument name will get stripped from the kwargs.此外,随着这些参数的传递,每个唯一的参数名称都将从 kwargs 中删除。 So this means that you can't reuse name as an initialization argument.所以这意味着你不能重用name作为初始化参数。 I'll use worrior_name and archer_name instead.我将使用worrior_namearcher_name代替。 So putting this all together, the following will run each initializer only once, without crashing:因此,将所有这些放在一起,以下将只运行每个初始化程序一次,而不会崩溃:

class Player:
    def __init__(self, hp, **kwargs):
        print(super().__init__)
        self.hp = hp

    def sign_in(self):
        print('player sign in')


class Worrior(Player):
    def __init__(self, worrior_name, power, **kwargs):
        super().__init__(**kwargs)
        self.name = worrior_name
        self.power = power

    def __str__(self):
        return "The worrior's name: " f'{self.name} \n' \
               "He has the power:" f'{self.power}'


class Archer(Player):
    def __init__(self, archer_name, agility, **kwargs):
        super().__init__(**kwargs)
        self.name = archer_name
        self.agility = agility

    def __str__(self):
        return "The archer's name: " f'{self.name} \n' \
               "He has the agility:" f'{self.agility}'


class Boss(Worrior, Archer):
    def __init__(self, name, power, agility, hp):
        super().__init__(archer_name=name, worrior_name=name, power=power, agility=agility, hp=hp)

    def __str__(self):
        return "The boss's name: " f'{self.name} \n' \
               "With Worrior's power " f'{self.power} \n' \
               "and With Archer's agilit" f'{self.agility}' \
               "The boss' hp is: " f'{self.hp}'

This is happening because of the method resolution order (MRO) in new style classes.这是因为新样式类中的方法解析顺序(MRO) MRO of the Boss class -老板的MRO class -

ipdb> Boss.mro()                                                                                                                   
[<class '__main__.Boss'>, <class '__main__.Worrior'>, <class '__main__.Archer'>, <class '__main__.Player'>, <class 'object'>]
ipdb>  

This means that super() calls in Worrior class is actually referring to Archer, not Player.这意味着 Worrior class 中的 super() 调用实际上是指 Archer,而不是 Player。

You can refer to this stack overflow post - Method Resolution Order (MRO) in new-style classes?您可以参考这篇堆栈溢出帖子 - 新型类中的方法解析顺序(MRO)? , which explains nicely how MRO works in python. ,很好地解释了 MRO 在 python 中的工作原理。

It appears that Python decides to walk the entire hierarchy again when it arrives at super() in the Warrior class (I've corrected your spelling, it's not 'Worrior').看来 Python 决定在到达勇士 class 中的super()时再次遍历整个层次结构(我已经更正了您的拼写,它不是“勇士”)。

I'm not sure where you're going wrong or whether this is just a situation where you cannot use super() .我不确定你哪里出错了,或者这是否只是你不能使用super()的情况。 I expected the same as you and was surprised by the result as well.我的预期和你一样,结果也让我感到惊讶。

However, the code below doesn't have the problem, although you of course lose the flexibility and I don't like having to do this:但是,下面的代码没有问题,虽然你当然失去了灵活性,我不喜欢这样做:

class Player:
    def __init__(self, hp):
        self.hp = hp

    def sign_in(self):
        print('player sign in')


class Warrior(Player):
    def __init__(self, name, power, hp):
        Player.__init__(self, hp)
        self.name = name
        self.power = power

    def __str__(self):
        return "The warrior's name: " f'{self.name} \n' \
            "He has the power:" f'{self.power}'


class Archer(Player):
    def __init__(self, name, agility, hp):
        Player.__init__(self, hp)
        self.name = name
        self.agility = agility

    def __str__(self):
        return "The archer's name: " f'{self.name} \n' \
            "He has the agility:" f'{self.agility}'


class Boss(Warrior, Archer):
    def __init__(self, name, power, agility, hp):
        Warrior.__init__(self, name, power, hp)
        Archer.__init__(self, name, agility, hp)

    def __str__(self):
        return "The boss's name: " f'{self.name} \n' \
            "With Warrior's power: " f'{self.power} \n' \
            "and With Archer's agility: " f'{self.agility}'\
            "The boss' HP is: " f'{self.hp}'


boss = Boss("Boss", 50, 50, 100)
print(boss.__str__())

So, not really a complete answer, but wanted to provide the feedback - hope someone else provides a complete answer with an explanation of what is really going on.所以,并不是一个完整的答案,而是想提供反馈——希望其他人提供一个完整的答案,并解释到底发生了什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM