3

super()を使用する場合と親クラス名を直接使用する場合の違いはありますか?たとえば:super()とParentクラス名の違いは何ですか?

class Parent: 
    def __init__(self): 
     print("In parent") 
     self.__a=10 

class Child(Parent): 
    def __init__(self): 
     super().__init__()  # using super() 
     Parent.__init__(self) # using Parent class name 

c=Child() 

は内部super().__init__()Parent.__init__(self)の違いはありますか?

+0

'super()'は、** MRO ** ... –

+0

を使用してコールを解決します。サブクラスが複数のスーパークラスを持つ場合、またはある時点で継承するサブクラスを変更する場合は、別のスーパークラス。 Btw、 "親クラス"は、継承のための通常の用語ではありません。 – khelwood

+0

@khelwood厳密に言えば、そうではありません。複数の継承を持つクラスをサブクラス化すると、 'super()'は実際には親ではなくslibingに委譲できます。単に '__mro__'の次の行を返します。 –

答えて

6

このケース。しかし、一般的で、そしてdocumentationに指定されているようあなたはメソッド解決順序(MRO)の次のオブジェクトに多重継承super()デリゲートを使用し、特に:

super([type[, object-or-type]])

代理オブジェクトを返します。メソッド呼び出しを親に委譲するか、 siブラインドクラスのタイプ。これは、クラスでオーバーライドされている継承されたメソッド にアクセスする場合に便利です。検索の順序は、がgetattr()で使用されているのと同じですが、タイプ自体はスキップされます。

タイプの__mro__属性がgetattr()super()の両方で使用されるメソッド解決の検索順序を示しています。属性 は動的であり、継承階層が更新されるたびに変更される可能性があります。

(...)

例えばあなたが(this question, where the MRO is discussed in more detailから借りのようなクラスを定義する(コピー、太字が追加)

セイ):

class F: 
    def __init__(self): 
     print('F%s'%super().__init__) 
     super().__init__() 

class G: 
    def __init__(self): 
     print('G%s'%super().__init__) 
     super().__init__() 

class H: 
    def __init__(self): 
     print('H%s'%super().__init__) 
     super().__init__() 

class E(G,H): 
    def __init__(self): 
     print('E%s'%super().__init__) 
     super().__init__() 

class D(E,F): 
    def __init__(self): 
     print('D%s'%super().__init__) 
     super().__init__() 

class C(E,G): 
    def __init__(self): 
     print('C%s'%super().__init__) 
     super().__init__() 

class B(C,H): 
    def __init__(self): 
     print('B%s'%super().__init__) 
     super().__init__() 

class A(D,B,E): 
    def __init__(self): 
     print('A%s'%super().__init__) 
     super().__init__() 

その後A__mro__がある:

A.__mro__ == (A,D,B,C,E,G,H,F,object) 

A()と呼ぶと、

A<bound method D.__init__ of <__main__.A object at 0x7efefd8645c0>> 
D<bound method B.__init__ of <__main__.A object at 0x7efefd8645c0>> 
B<bound method C.__init__ of <__main__.A object at 0x7efefd8645c0>> 
C<bound method E.__init__ of <__main__.A object at 0x7efefd8645c0>> 
E<bound method G.__init__ of <__main__.A object at 0x7efefd8645c0>> 
G<bound method H.__init__ of <__main__.A object at 0x7efefd8645c0>> 
H<bound method F.__init__ of <__main__.A object at 0x7efefd8645c0>> 
F<method-wrapper '__init__' of A object at 0x7efefd8645c0> 
<__main__.A object at 0x7efefd8645c0> 

ので、Aの文脈におけるそのを意味し、その__init__を得るためをしようとすると:A

  • super().__init__D.__init__です。
  • super().__init__Dは、B.__init__です。
  • super().__init__Bは、C.__init__である。
  • super().__init__Cは、E.__init__である。
  • super().__init__Eは、G.__init__です。
  • super().__init__Gは、H.__init__である。
  • super().__init__Hは、F.__init__である。
  • super().__init__Fは、object.__init__である。これsuper()が親にない自体の代表をしていること

注意。たとえば、がDの場合はBBの場合はDというスーパークラスではないため、実際にははオブジェクトのタイプ()に依存します。

は今Dの場合には、__mro__は次のとおりです。

D.__mro__ = (D,E,G,H,F,object) 

我々はDを構築した場合しかし、我々が得る:

D<bound method E.__init__ of <__main__.D object at 0x7efefd864630>> 
E<bound method G.__init__ of <__main__.D object at 0x7efefd864630>> 
G<bound method H.__init__ of <__main__.D object at 0x7efefd864630>> 
H<bound method F.__init__ of <__main__.D object at 0x7efefd864630>> 
F<method-wrapper '__init__' of D object at 0x7efefd864630> 

を、それがあることを保持しているので、Dの文脈で

  • super().__init__Dは、E.__init__です。
  • super().__init__Eは、G.__init__です。
  • super().__init__Gは、H.__init__である。
  • super().__init__Hは、F.__init__である。
  • super().__init__Fは、object.__init__である。 Aの文脈では同じではありません
  • Dの だからここ

super()は(__init__用)Eにつながる

+1

私はあなたが最も重要な'A'の' super() 'が' D'に委譲し、 'D'の' super() '呼び出しが' B'に委譲しますが、 D'インスタンスの 'super()'呼び出しは 'E'になります。 – Duncan

+0

@ダンカン:まったく、更新された回答を参照してください。 –

+1

はい、あなたの編集は私のコメントと交差しました。私はまだ直接Dインスタンスの 'super()'がどこか違うことを示すことは有用だと思っていますが、はるかに優れています。 – Duncan

1
super().__init__(*args, **kwargs) 

「自己」に合格しないと認識します。自動的に挿入されます。

super()は、最初のクラスは、そのすぐ上のスーパークラスが変更される可能性があることのようにクラス階層におけるミックスインとして再利用できるようにするためのPython 2に設計されました:時間の中でいくつかの点で

レッツ・suposeあなたのコードは次のようである:

この時点で
class A: pass 
class B(A): 
    def __init__(self, *args, **kwargs): 
      ... 
      # Fixed call to A 
      A.__init__(self, *args, **kwargs) 

class C(A): 
    def __init__(self, *args, **kwargs): 
      ... 
      # Fixed call to A 
      A.__init__(self, *args, **kwargs) 

class D(C, B): 
    pass 

、正しいOOPコードがB.__init__への呼び出しをチェーンする必要がありC.__init__を実行する必要がありますが、スーパークラス名が起こらないようにハードコードされた - A__init__は常に次来ます。 B.__init__Cにハードコードすると、がBなしで機能しないようになり、複数の継承の目的を破ることになります。

あなたの代わりにsuper()を使用する場合は、Pythonのクラスの__mro__属性に見て次の親クラスのメソッドを検索し(MRO =メソッド解決順序。__mro__は各Pythonクラスに添付具体的な属性である)を行います。 - したがって、上記の時差クラスDのある時点で、Bから継承されなくなった場合、super().__init__への呼び出しはCに自動的にAに自動的に再ルーティングされます。

というパラメータのない形式は、その使用を容易にするために導入されました。その前に、独自のクラスへの参照をハードコードし、パラメータにselfを挿入する必要がありました。このフォームは、コンパイラ自体にハードコードされているPythonのほんの一部の例外の1つです。super(または__class__)がメソッド本体の中にある場合(つまり、クラス自体を指す変数__class__が作成されたときsuperコールが使用する)