262

この質問にはすでに答えがあります。

これを考えてみましょう - 基本クラスA、Aから継承したクラスB、Bから継承したクラスC。コンストラクタで親クラスのコンストラクタを呼び出す一般的な方法は何ですか?それでも曖昧に聞こえるなら、ここにいくつかのコードがあります。

class A(object):
    def __init__(self):
        print "Constructor A was called"

class B(A):
    def __init__(self):
        super(B,self).__init__()
        print "Constructor B was called"

class C(B):
    def __init__(self):
        super(C,self).__init__()
        print "Constructor C was called"

c = C()

これが私が今やる方法です。しかし、それはまだ少し一般的ではないように見えます - あなたはまだ手で正しい型を渡さなければならない。

今、使ってみましたself.__class__super()への最初の引数として、しかし、明らかにそれは機能しません - あなたがそれをCのためのコンストラクタに入れた場合 - かなり公平、Bのコンストラクタが呼ばれます。 Bで同じことをしても、 "self"はまだCのインスタンスを指しているので、Bのコンストラクタを再度呼び出すことになります(これは無限再帰で終わります)。

今のところダイヤモンドの継承について考える必要はありません、私はこの特定の問題を解決することに興味があるだけです。


  • 「しかし、それでもやや一般的ではないように思われます - あなたはまだ手で正しい型を渡さなければなりません。」???あなたはクラス名をsuper()に渡しています。あなたはスーパークラスや他の何かを知る必要はありません。これはどのように非ジェネリックですか?それはどんな問題を引き起こしますか?これが壊れる例を挙げていただけますか。 - S.Lott
  • いっぱいになったら、私はこの質問に答える準備ができていません。しかし、とにかく、クラスの名前が変更されたらどうなりますか?このような連鎖を自動化するためのデコレータ関数を作成したい場合はどうすればいいですか?今、私はこれが不可能であることを見ます、しかし質問をする時に私はそれを知りませんでした。 - shylent
  • @ shylent、私があなたの質問を理解したら、あなたの説明は可能です。 mroを理解していれば、super()を使用して親参照を完全に総称にすることができます。 Googleの「python super is super」の動画をご覧ください。 - Jamie Marshall
  • 実際のところ、あなたの質問をもう一度読みます。あなたが経験している無限の再帰は、あなたがそれを思っていることではないと私は信じています。 mro命令により、あなたが意図しないコンストラクタを呼び出すようになっていると思います。私は昔、私自身がこれと同じことに対処しました。 superの最初の引数に何を渡しても、superは渡した型ではなくmroの最初のコンストラクタを呼び出します。たとえば、Cのコンストラクタでsuper(self .__ class__、self)を呼び出すと、それはmroの最初の親なので、それでもBのコンストラクタを呼び出します。 - Jamie Marshall

3 답변


161

あなたがしている方法は確かに(Python 2.xのために)お勧めの方法です。

クラスが明示的にに渡されるかどうかの問題super機能よりもスタイルの問題です。にクラスを渡すsuperPythonの「明示的は暗黙的より優れている」という哲学に適合します。


  • どちらの回答を受け入れるかを決めるのは非常に困難でしたが、これは私が使用しているpythonのバージョンに関連しているという理由だけで受け入れます。 - shylent
  • Python 2.6では、TypeError: super() argument 1 must be type, not classobjこの方法を使用します。私は何かが足りないのですか? - Leopd
  • @Leopd:super()新しいスタイルのクラスでのみ動作します。つまり、から継承する必要があります。object。 - dF.
  • Pythonは強く型付けされた言語ですが、動的に型付けされています。弱い型付けと動的型付けには違いがあります。 - Josh Smeaton
  • @TheScience定義は明らかです。 Pythonは強力で動的です。 Javaのようなものは強い静的です。 PHPは弱い動的です。静的型付けは、(少なくともいくつかの制限内で)入力パラメータが正しい型であることを保証します。強い型付けは、コンパイラ/ランタイムが、型変換を強制しようとしないことを意味します。「1」を変更するのと同じです。あなたはそれに数学を行うことができるように1に。こちらをご覧ください。wiki.python.org/moin/… - Josh Smeaton

176

Python 3には、このように使えるように改良されたsuper()が含まれています。

super().__init__(args)


  • 私が複数の親クラスを持っている場合、どの親クラスを呼び出すかをsuperがどのように識別するのでしょうか。 - Kracekumar
  • @kracekumarクラスによって決定されます'メソッド解決順序(MRO)、これを呼び出すことで確認できます。MyClassName.mro()。私は間違っているかもしれませんが、最初に指定された親は、__init__と呼ばれます。 - Cam Jackson
  • @ironfroggy、この改善されたスーパーはどのように問題解決に役立つのでしょうか。私はちょうどこの古いスレッドを見つけました、そして私は同じ正確な質問をしています。この質問が最初に尋ねられて以来、物事はPython 2.xのために改良されましたか? - Amelio Vazquez-Reina
  • @ user815423426これによってアップコールがより一般的になり、元の質問の主題であったクラス名が繰り返されなくなりました。 - ironfroggy
  • @kracekumar、super(X、obj)は実際には特別な" super"を返します。あなたがそれに対して属性アクセスをするとき、クラスXが全く属性を持っていなかったならば返されたであろう属性を返すオブジェクト。例えば、super(X、obj).__ init__は、その中にあたかもあなたのobjのメソッドその中にクラスXではありませんでした。今、クラスXが2つの親を持ち、X .__ init__が存在しない場合、デフォルトの振る舞いは以下を呼び出すことです。その中にのみの1両方ではなく、両親のこれは事実上スーパーがやっていることです...あなたに両親の一人を与えます。 - Chris Cogdon

24

あなたは簡単に書くことができます:

class A(object):

    def __init__(self):
        print "Constructor A was called"

class B(A):

    def __init__(self):
        A.__init__(self)
        # A.__init__(self,<parameters>) if you want to call with parameters
        print "Constructor B was called"

class C(B):

    def __init__(self):
        # A.__init__(self) # if you want to call most super class...
        B.__init__(self)
        print "Constructor C was called"

リンクされた質問


関連する質問

最近の質問