web-dev-qa-db-ja.com

スーパーコンストラクタを呼び出す方法

class A:
    def __init__(self):
        print("world")

class B(A):
    def __init__(self):
       print("hello")

B()  # output: hello

私がスーパーコンストラクタで作業した他のすべての言語では、暗黙のうちに呼び出されます。 Pythonでそれを呼び出す方法は?私はsuper(self)を期待するでしょうが、これはうまくいきません。

300
Mike

super()は親のようなオブジェクトを返します新しいスタイルのクラスでは

class A(object):
    def __init__(self):
        print "world"

class B(A):
    def __init__(self):
        print "hello"
        super(B, self).__init__()

B()
296

他の答えに沿って、スーパークラスメソッド(コンストラクタを含む)を呼び出す方法は複数ありますが、Python-3.xではプロセスが単純化されました。

Python-2.x

class A(object):
 def __init__(self):
   print "world"

class B(A):
 def __init__(self):
   print "hello"
   super(B, self).__init__()

Python-3.x

class A(object):
 def __init__(self):
   print("world")

class B(A):
 def __init__(self):
   print("hello")
   super().__init__()

super()ドキュメント のようにsuper(<containing classname>, self)と同等になりました。

193
Aidan Gomez

Python 2.xの旧式のクラスではこれは次のようになります。

class A: 
 def __init__(self): 
   print "world" 

class B(A): 
 def __init__(self): 
   print "hello" 
   A.__init__(self)
52
Gabe

1つの方法は、Aのコンストラクタを呼び出し、引数としてselfを渡すことです。

class B(A):
    def __init__(self):
        A.__init__(self)
        print "hello"

このスタイルの利点は非常に明確です。それはAのイニシャライザと呼ばれます。欠点は、共有基本クラスのイニシャライザを2回呼び出すことになる可能性があるため、ひし形の継承をうまく処理できないことです。

他の方法は、他の人が示しているように、super()を使うことです。単一継承の場合、それは基本的に親のイニシャライザを呼ばせるのと同じことをします。

しかし、super()は内部ではかなり複雑で、複数の継承状況では直感的に理解しにくい場合があります。プラス面では、super()を使用して菱形の継承を処理できます。あなたがsuper()が何をするのかについての重要性を知りたければ、super()がどのように機能するかについて私が見つけた最良の説明は ここ です(私は必ずしもその記事の意見を支持しません) 。

32

短い答え

super(DerivedClass, self).__init__()

長い答え

super()は何をするのですか?

それは指定されたクラス名を取り、その基本クラスを見つけ(Pythonは多重継承を許します)、そしてそれらのそれぞれで左から右へメソッド(この場合は__init__)を探します。利用可能なメソッドが見つかるとすぐにそれを呼び出して検索を終了します。

すべての基底クラスのinitを呼び出すにはどうすればいいですか?

基本クラスが1つしかない場合は上の例がうまくいきます。しかし、Pythonでは多重継承が許可されているため、すべての基本クラスが正しく初期化されていることを確認することをお勧めします。そのためには、各基本クラスにinitを呼び出す必要があります。

class Base1:
  def __init__():
    super(Base1, self).__init__()

class Base2:
  def __init__():
    super(Base2, self).__init__()

class Derived(Base1, Base2):
  def __init__():
    super(Derived, self).__init__()

initをsuperの呼び出しを忘れた場合はどうなりますか?

コンストラクタ(__new__)はチェーンで呼び出されます(C++やJavaの場合と同様)。インスタンスが作成されると、そのインスタンスの初期化子(__init__)のみが呼び出され、そのスーパークラスへの暗黙の連鎖はありません。

2
Shital Shah

私は以前の答えを拡張する次の公式を使います。

class A(object):
 def __init__(self):
   print "world"

class B(A):
 def __init__(self):
   print "hello"
   super(self.__class__, self).__init__()

B()

こうすれば、superの呼び出しでクラスの名前を繰り返す必要はありません。大量のクラスをコーディングしていて、初期化メソッド内のコードをクラス名から独立させたい場合に便利です。

1
lackadaisical

パラメータ付きの例を追加するだけです:

class B(A):
    def __init__(self, x, y, z):
        A.__init__(self, x, y)

変数x、y、zの定義を必要とする派生クラスBと、x、yの定義を必要とするスーパークラスAを指定すると、スーパークラスAの静的メソッドinitを呼び出すことができます現在のサブクラスインスタンス(自己)への参照、および予想される引数のリスト。

0
gal007