简体   繁体   English

Python - 这是调用超类'方法的更好方法吗?

[英]Python - which is the better way of calling superclass' method?

All the while I have been using: 我一直在使用:

SuperClass.__init__(self, *args, **kwargs)

My reason is that this shows explicitly which superclass is used, especially in the case of multiple inheritance. 我的理由是,它明确地显示了使用哪个超类,特别是在多重继承的情况下。

However, other codes I came across use 但是,我遇到的其他代码使用

super(MyClass, self).__init__(*args, **kwargs)

instead. 代替。

This could become ambigious when it's used in: 在用于以下情况时,这可能会变得暧昧:

class MyClass(SuperClass1, SuperClass2):
    def __init__(self, *args, **kwargs):
        super(MyClass, self).__init__(*args, **kwargs) #which SuperClass is being used?

I would like to know why this form of calling is widely adopted? 我想知道为什么这种呼叫形式被广泛采用? Any advantage at all? 有什么优势吗?

The reason that super is prefereable for modern ( new style ) classes is that it allows cooperative multiple inheritance. super适用于现代( 新风格 )类的原因是它允许合作多重继承。 Here's an example. 这是一个例子。

>>> class Foo(object):
...     def display(self):
...         print "In Foo"
... 
>>> class Foo2(Foo):
...     def display(self):
...         print "In Foo2"
...         super(Foo2, self).display()
...         print "Back in Foo2"
... 
>>> class Bar(Foo):
...     def display(self):
...         print "In Bar"
...         super(Bar, self).display()
...         print "Back in Bar"
... 
>>> class FooBar(Foo2, Bar):
...     pass
... 
>>> FooBar().display()
In Foo2
In Bar
In Foo
Back in Bar
Back in Foo2
>>> class BarFoo(Bar, Foo2):
...     pass
... 
>>> BarFoo().display()
In Bar
In Foo2
In Foo
Back in Foo2
Back in Bar

Note that I didn't do anything to change the display method on the superclasses but I got different display methods on the subclasses by changing the order in which I arranged the superclasses. 请注意,我没有做任何事情来改变超类上的display方法,但是通过改变我安排超类的顺序,我在子类上有不同的display方法。 BarFoo and FooBar have different methods. BarFooFooBar有不同的方法。 This is because they have different Method Resolution Orders 这是因为他们有不同的方法解决方案订单

>>> BarFoo.__mro__
(<class '__main__.BarFoo'>, <class '__main__.Bar'>, <class '__main__.Foo2'>, <class '__main__.Foo'>, <type 'object'>)
>>> FooBar.__mro__
(<class '__main__.FooBar'>, <class '__main__.Foo2'>, <class '__main__.Bar'>, <class '__main__.Foo'>, <type 'object'>)

This means that super resolves to a different class for each subclass that it's called in. This allows for each overriding method to change a small part of what's going on and still let every other superclass contribute to the method call as long as they're willing to play nicely. 这意味着super为每个被调用的子类解析为一个不同的类。这允许每个重写方法改变正在进行的一小部分,并且只要他们愿意,仍然允许每个其他超类对方法调用做出贡献。好好玩。

For new style classes which inherit from object , super is used. 对于从object继承的新样式类,使用super

The __mro__ (method resolution order) attribute of the type lists the method resolution search order used by super . 所述__mro__类型的(方法解析顺序)属性列出了所使用的方法的分辨率搜索顺序super

>>> class X(object):
    pass

>>> class Y(object):
    pass

>>> class Z(X, Y):
    pass

>>> Z.__mro__
(<class '__main__.Z'>, <class '__main__.X'>, <class '__main__.Y'>, <type 'object'>)

This specifies the ordering for Z. Since it is Z(X, Y) , X is first in the hierarchy. 这指定了Z的排序。因为它是Z(X, Y) ,所以X在层次结构中是第一个。 Had it been Z(Y, X) , Y would have preceded over X . 如果它是Z(Y, X)Y将超过X

For old style classes, SuperClass.__init__(self, *args, **kwargs) is used. 对于旧样式类,使用SuperClass.__init__(self, *args, **kwargs)

UPDATE: 更新:

For your question as to which SuperClass is being used. 关于使用哪个SuperClass问题。

>>> class First(object):
    pass

>>> class Second(object):
    def __init__(self, *args, **kwargs):
        print 'Second __init__ called'

>>> class MInherit(First, Second):
    def __init__(self):
        super(MInherit, self).__init__()

>>> i = MInherit()
Second __init__ called

First, First will be checked to see if it has an __init__ , since First comes first in the MRO. 首先,将检查First是否有__init__ ,因为First在MRO中排在第一位。 Since in this case 'First' doesn't have an __init__ , so Second is called. 因为在这种情况下'First'没有__init__ ,所以Second被调用。 Had there been an __init__ in First , only that would have been called. 如果在First__init__ ,那么只会被调用。

In addition to the good answers already posted, here is some additional info: 除了已经发布的好答案,这里还有一些额外的信息:

  • Old-style classes (those that don't derive from object) have a depth-first method resolution order. 旧式类(不是从对象派生的类)具有深度优先的方法解析顺序。 Old-style classes call their super classes in the way that you are used to. 旧式类以您习惯的方式调用它们的超类。

  • New-style classes (those that do derive from object) have a more complicated method resolution order. 新样式的类(从对象派生的类)具有更复杂的方法解析顺序。 At the highest level it is akin to breadth first, but is more complex than that. 在最高级别,它首先类似于广度,但比这更复杂。 See this page for an excellent explanation. 请参阅此页面以获得出色的解释。 Using "super()" allows new style classes to follow this method resolution order. 使用“super()”允许新样式类遵循此方法解析顺序。

  • If you are using new-style classes, you can still use the old-style of calling super classes and your code will still work. 如果您正在使用新式类,您仍然可以使用旧式调用超类,您的代码仍然可以使用。 The differences only become apparent for more complicated multiple-inheritance patterns. 只有更复杂的多继承模式才会出现差异。

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

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