2011-02-17 59 views
48

我到处看到的例子是超一流的方法应该由被称为:Python的超级方法调用替代

super(SuperClass, instance).method(args) 

是否有任何缺点做:

SuperClass.method(instance, args) 

回答

96

考虑以下情况:

class A(object): 
    def __init__(self): 
     print('Running A.__init__') 
     super(A,self).__init__() 
class B(A): 
    def __init__(self): 
     print('Running B.__init__')   
     # super(B,self).__init__() 
     A.__init__(self) 

class C(A): 
    def __init__(self): 
     print('Running C.__init__') 
     super(C,self).__init__() 
class D(B,C): 
    def __init__(self): 
     print('Running D.__init__') 
     super(D,self).__init__() 

foo=D() 

因此类形成所谓的继承钻石:

A 
/\ 
    B C 
    \/
    D 

运行代码产量

Running D.__init__ 
Running B.__init__ 
Running A.__init__ 

这是不好的,因为C“ s跳过了__init__。原因是因为B__init__直接调用A__init__

super的用途是解决继承钻石。如果您取消注释

# super(B,self).__init__() 

和注释掉

A.__init__(self) 

代码产生了更多desireable结果:

Running D.__init__ 
Running B.__init__ 
Running C.__init__ 
Running A.__init__ 

现在所有的__init__方法被调用。请注意,在您定义B.__init__时,您可能会认为认为 0123'与呼叫A.__init__(self)相同,但您会错误的。在上述情况下,super(B,self).__init__()实际上调用C.__init__(self)

圣烟,B一无所知C,然而super(B,self)知道调用C__init__?原因是因为self.__class__.mro()包含C。换句话说,self(或上面的foo)知道约C

所以要小心 - 两者不可互换。他们可以产生截然不同的结果。

使用superhas pitfalls.在继承关系图中的所有类之间需要相当程度的协调。 (他们必须,例如,或者具有相同的调用签名为__init__,因为任何特定__init__不知道其他__init__super下一步可能调用,或其他 use **kwargs)。此外,你必须是有关使用super到处是一致的。跳过一次(如上面的例子),你击败了super的整个目的。 查看更多陷阱的链接。

如果您完全控制了您的类层次结构,或者避免了继承菱形,那么不需要super

+2

+1为超级有害链接。我即将自己发布。 – 2011-02-17 20:47:59

7

有没有处罚的,是,尽管你的例子有些误导。在第一个例子,它应该是

super(SubClass, instance).method(args) # Sub, not SuperClass 

,并导致我引用了Python docs

有两个典型的用例super的。在具有单一继承的类层次结构中,可以使用super来引用父类而不显式命名它们,从而使代码更易于维护。这种用法与其他编程语言中使用的super非常类似。

第二个用例是在动态执行环境中支持协作多重继承。这个用例是Python独有的,在静态编译的语言或仅支持单一继承的语言中找不到。这使得在多个基类实现相同方法的情况下实现“菱形图”成为可能。良好的设计规定,这种方法在每种情况下都具有相同的调用签名(因为调用顺序是在运行时确定的,因为该顺序适用于类层次结构中的更改,并且因为该顺序可以包含运行时未知的同级类)。

基本上,使用第一种方法,你不要使用有硬编码的父类中有单级的层次,你根本就没有真正做你想做的(有效/有效)使用多重继承时的第二种方法。

+1

我是否理解正确,在单一继承情况下没有使用`超级`的缺点? – Wolf 2015-02-02 10:08:41