2017-07-29 18 views
0

呼び出すと、私は次のコードを持っている:多重継承でのスーパークラスメソッド

class A: 
    pass 

class B(A): 
    def foo(self, a): 
     if a: 
      return 'B' 
     return super(B, self).foo(a) 

class C: 
    def foo(self, a): 
     return 'C' 

class D(B, C): 
    def foo(self, a): 
     return super().foo(a) 

d = D() 
print(d.foo(0)) 

私はMROに基づいd.foo(0)を呼び出すと、それは最初Bクラスのfooメソッドを呼び出して、その内部に、条件が間違っている場合は、それをsuper(B, self).foo(0)を返すが、クラスAにはfooメソッドを持っていないし、私はこのエラーを期待しています:

AttributeError: 'super' object has no attribute 'foo' 

が、それはクラスCから'C'を返します。どうして?

+1

これは「スーパー」の全体的なポイントです。それについて考えてみましょう。親に直接電話するのであれば、その言語では「スーパー」は必要ないでしょう。ここで直接「A」と呼ぶことにします。 – wim

答えて

1

super()は、次のクラスの属性を持つのMROを検索します。 Aはまだ実装されていないので、Cが考慮されています。 B.fooを見つけるDにおけるようsuper().foo

>>> D.__mro__ 
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class 'object'>) 

、及びB.fooから、Aはスキップされ、C.fooが見出される;

Dため、MROは、ABDCありますあなたは、対話型インタプリタからこの自分自身をテストすることができます。

>>> super(D, d).foo 
<bound method B.foo of <__main__.D object at 0x1079edb38>> 
>>> super(B, d).foo 
<bound method C.foo of <__main__.D object at 0x1079edb38>> 

これは、属性検索アルゴリズムのPython実装は次のようになります。

type_super()の最初の引数(クラスで
def find_attribute(type_, obj, name): 
    starttype = type(obj) 
    mro = iter(starttype.__mro__) 

    # skip past the start type in the MRO 
    for tp in mro: 
     if tp == type_: 
      break 

    # Search for the attribute on the remainder of the MRO 
    for tp in mro: 
     attrs = vars(tp) 
     if name in attrs: 
      res = attrs[name] 
      # if it is a descriptor object, bind it 
      descr = getattr(type(res), '__get__', None) 
      if descr is not None: 
       res = descr(
        res, 
        None if obj is starttype else obj, 
        starttype) 
      return res 

メソッドが定義されています)、objがインスタンスです(ここではtype(d)なので)。nameは、探している属性です。