Trouble understanding super() when calling multiple parents

五迷三道 提交于 2019-12-13 03:50:02

问题


I've been doing research on Python 3 (my code sample uses 3.7.2) and how to properly use super() when a class inherits more than one class.

I've read this page, and this page and this article. I think the problem is that the SO links are for an older version of Python, while the article is for Python 3, but it's still confusing.

Suppose I had the following code (don't worry if you think that the relationship can be modeled better, this is just an example to illustrate my problem):

class Weapon:

    def __init__(self, name, damage):
        self.name = name
        self.damage = damage

class Reloadable:

    def __init__(self, amount):
        self.amount = amount

class Sniper(Weapon, Reloadable):

    def __init__(self, name, damage, amount, scope_type):
        super().__init__(name, damage)
        super().__init__(self, amount)
        self.scope_type = scope_type

    def adjust_scope(self):
        print("Adjusting my scope")

Main:

gun = Sniper("Standard Sniper", 10, 20, "small")
gun.adjust_scope()

print(Sniper.__mro__)

and the MRO:

(<class 'inheritnacewithsuper.Sniper'>, 
 <class 'inheritnacewithsuper.Weapon'>, 
 <class 'inheritnacewithsuper.Reloadable'>, <class 'object'>)

The code works and called the desired parent classes, but I want to make sure, when using Python 3.7, and super(), is doing super().__init__(name, damage) and super().__init__(self, amount), the correct way to initialize the parent constructors?

The article doesn't do that, instead it called the super() for only one class (RightPyramid(Square, Triangle)).

I just want to make sure I'm on the right track, and using proper practices.


回答1:


super() requires your code cooperates. Your Weapon and Reloadable classes don't, so you actually don't want to use super() here. You'd call the unbound methods directly on those base classes:

class Sniper(Weapon, Reloadable):
    def __init__(self, name, damage, amount, scope_type):
        Weapon.__init__(self, name, damage)
        Reloadable.__init__(self, amount)
        self.scope_type = scope_type

Without super(), the __init__ methods are unbound so you need to pass in self explicitly.

See super() considered super! by Python core developer Raymond Hettinger (or the Python conference presentation of the same name for a great overview how to use super() in a cooperative manner.

To be fully cooperative, all classes in your hierarchy should pass on the super().<methodname>() calls in the chain of classes. With mix-in classes like Reloadable, you'd want to either use a base no-op class or handle errors when calling super().__init__(), or pass on arguments as keyword arguments, and have each __init__() method accept arbitrary keyword arguments to pass on again:

class Weapon:
    def __init__(self, name, damage, **kwargs):
        self.name = name
        self.damage = damage
        # pass on any remaining arguments
        super().__init__(**kwargs)

class Reloadable:    
    def __init__(self, amount, **kwargs):
        self.amount = amount
        # pass on any remaining arguments
        super().__init__(**kwargs)

class Sniper(Weapon, Reloadable):    
    def __init__(self, name, damage, amount, scope_type):
        self.scope_type = scope_type
        super().__init__(name=name, damage=damage, amount=amount)

    def adjust_scope(self):
        print("Adjusting my scope")


来源:https://stackoverflow.com/questions/54694707/trouble-understanding-super-when-calling-multiple-parents

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!