【问题标题】:Python - which is the better way of calling superclass' method?Python - 这是调用超类方法的更好方法?
【发布时间】:2011-05-17 02:09:32
【问题描述】:

我一直在使用:

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

我的原因是这明确显示了使用哪个超类,尤其是在多重继承的情况下。

但是,我遇到的其他代码使用

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

改为。

当它用于以下场合时可能会变得模棱两可:

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

我想知道为什么这种调用方式被广泛采用?有什么优势吗?

【问题讨论】:

    标签: python oop class


    【解决方案1】:

    对于继承自object 的新样式类,使用super

    type__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'>)
    

    这指定了 Z 的顺序。因为它是 Z(X, Y),所以 X 在层次结构中排在第一位。如果是Z(Y, X)Y 会优先于X

    对于旧式类,使用SuperClass.__init__(self, *args, **kwargs)

    更新:

    关于使用哪个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 是否有__init__,因为First 在MRO 中排在第一位。因为在这种情况下,'First' 没有__init__,所以调用了Second。如果First 中有一个__init__,那么只会调用它。

    【讨论】:

      【解决方案2】:

      super 更适合现代(新风格)类的原因是它允许合作 多重继承。这是一个例子。

      >>> 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
      

      请注意,我没有对超类上的display 方法进行任何更改,但是通过更改我排列超类的顺序,我在子类上获得了不同的display 方法。 BarFooFooBar 有不同的方法。这是因为它们有不同的方法解析顺序

      >>> 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'>)
      

      这意味着super 为调用它的每个子类解析为不同的类。这允许每个覆盖方法更改正在发生的事情的一小部分,并且仍然让所有其他超类对方法调用做出贡献因为他们愿意打得很好。

      【讨论】:

        【解决方案3】:

        除了已经发布的好的答案,这里还有一些附加信息:

        • 旧式类(那些不是从对象派生的)具有深度优先的方法解析顺序。旧式类以您习惯的方式调用它们的超类。

        • 新型类(确实从对象派生的类)具有更复杂的方法解析顺序。在最高级别,它类似于广度优先,但比这更复杂。请参阅此page 以获得出色的解释。使用“super()”允许新样式类遵循此方法解析顺序。

        • 如果您使用的是新式类,您仍然可以使用旧式调用超类,并且您的代码仍然可以工作。只有在更复杂的多重继承模式中,差异才会变得明显。

        【讨论】:

          猜你喜欢
          • 2010-12-15
          • 1970-01-01
          • 1970-01-01
          • 2021-11-10
          • 1970-01-01
          • 2011-12-08
          • 1970-01-01
          • 2011-07-03
          • 1970-01-01
          相关资源
          最近更新 更多