139

私はObjective-Cでそれを使用しています:私はこの構成を持っています:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

Pythonは、親クラスの実装も呼び出す必要があり__init__ますか?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

__new__()これもとの真/偽__del__()ですか?

編集:非常によく似た質問があります:Pythonでの継承とオーバーライド__init__

4

7 に答える 7

154

__init__現在のクラスで行われていることに加えて、スーパーから何かを行う必要がある場合__init__,は、それを自分で呼び出す必要があります。これは自動的には行われないためです。しかし、スーパーから何も必要ない場合は、__init__,それを呼び出す必要はありません。例:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del____del__同じ方法です(ただし、ファイナライズに依存することに注意してください。代わりにwithステートメントを使用して実行することを検討してください)。

私はめったに使用__new__. しません私はですべての初期化を行います__init__.

于 2009-09-06T14:51:06.783 に答える
122

アノンの答えでは: 「現在のクラスで行われていることに加えて
、スーパーから何かを行う必要がある場合は、それを自分で呼び出す必要があります。これは自動的に行われないためです」__init____init__

信じられないことです。彼は、継承の原則とは正反対のことを言っています。


「スーパーの__init__ (...)からの何かが自動的に起こらない」ということではなく、自動的に起こるということですが、基本クラス__init__が派生クラスの定義によってオーバーライドされるため、起こりません。__init__

それでは、なぜ派生クラスを定義するの__init__でしょうか?

これは、基本クラスでは実行されない何かを定義する必要があり、それを取得する唯一の可能性は、その実行を派生クラスの関数__init__に入れることだからです。 言い換えれば、ベースクラスがオーバーライドされていない場合にベースクラスで自動的に行われるものに加えて、ベースクラスで何かが必要です。 その逆ではありません。 __init__
__init____init__


次に、問題は、基本クラスに存在する目的の命令__init__がインスタンス化の時点でアクティブ化されないことです。この非アクティブ化を相殺するには、何か特別なことが必要です: base-class'によって実行される初期化を追加せずにKEEP__init__するために、base-class' を明示的に呼び出します。それはまさに公式ドキュメントで言われていることです:__init__

派生クラスのオーバーライド メソッドは、同じ名前の基本クラス メソッドを単純に置き換えるのではなく、実際には拡張する必要がある場合があります。基本クラス メソッドを直接呼び出す簡単な方法があります。単に BaseClassName.methodname(self, arguments) を呼び出すだけです。
http://docs.python.org/tutorial/classes.html#inheritance

それがすべての話です:

  • 目的が基本クラスによって実行される初期化を維持すること、つまり純粋な継承である場合、特別なことは何も必要ありません__init__。派生クラスで関数を定義することを避ける必要があります

  • 目的が基本クラスによって実行される初期化を置き換えることである場合__init__、派生クラスで定義する必要があります

  • 基本クラスによって実行される初期化にプロセスを追加することが目的の場合、基本クラス__init__ への明示的な呼び出しを含む派生クラスを定義する必要があります。__init__


Anon の投稿で私が驚くべきことは、彼が継承理論の反対を表明したことだけではなく、5 人の男が髪を向けることなく賛成票を投じて通りかかったことであり、さらに 2 年間で誰も反応しませんでした。興味深いテーマを比較的頻繁に読まなければならないスレッド。

于 2011-08-14T20:31:39.267 に答える
70

Python では、スーパークラスの呼び出し__init__はオプションです。それを呼び出す場合、super識別子を使用するかどうか、またはスーパークラスに明示的に名前を付けるかどうかもオプションです。

object.__init__(self)

オブジェクトの場合、スーパー メソッドは空であるため、スーパー メソッドを呼び出す必要はありません。についても同じです__del__

一方、 for__new__の場合は、実際にスーパー メソッドを呼び出し、その戻り値を新しく作成されたオブジェクトとして使用する必要があります (明示的に別のものを返したい場合を除く)。

于 2009-09-06T14:18:07.693 に答える
23

編集:(コード変更後)親(または他の関数)
を呼び出す必要があるかどうかを通知する方法はありません。__init__継承は明らかにそのような呼び出しなしで機能します。それはすべてコードのロジックに依存します。たとえば、すべて__init__が親クラスで行われる場合は、子クラス__init__を完全にスキップできます。

次の例を検討してください。

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12
于 2009-09-06T14:11:23.533 に答える
6

厳格なルールはありません。クラスのドキュメントには、サブクラスがスーパークラスメソッドを呼び出す必要があるかどうかが示されている必要があります。スーパークラスの動作を完全に置き換えたい場合もあれば、それを拡張したい場合もあります。つまり、スーパークラスの呼び出しの前および/または後に独自のコードを呼び出します。

更新:同じ基本ロジックがすべてのメソッド呼び出しに適用されます。コンストラクターは特別な考慮が必要な場合があり(動作を決定する状態を設定することが多いため)、コンストラクターはコンストラクター(データベース接続などのリソースの割り当てなど)と並列であるためです。render()しかし、同じことが、たとえばウィジェットのメソッドにも当てはまる可能性があります。

さらなる更新: OPPとは何ですか?OOPのことですか?いいえ-サブクラスは、スーパークラスの設計について何かを知る必要があることがよくあります。内部実装の詳細ではなく、スーパークラスがクライアントとの間で持つ基本的な契約(クラスを使用)。これは、OOPの原則に違反するものではありません。これが、一般的にOOPで有効な概念である理由protectedです(もちろん、Pythonではそうではありませんが)。

于 2009-09-06T14:13:22.757 に答える
4

IMO、あなたはそれを呼ぶべきです。あなたのスーパークラスがであるならばobject、あなたはそうすべきではありませんが、他の場合にはそれを呼ばないことは例外的だと思います。__init__他の人がすでに答えているように、たとえば初期化する(追加の)内部状態がない場合など、クラスがそれ自体をオーバーライドする必要さえない場合は非常に便利です。

于 2009-09-06T14:47:43.030 に答える
2

はい、__init__良いコーディング プラクティスとして、常に基底クラスを明示的に呼び出す必要があります。これを忘れると、微妙な問題や実行時エラーが発生する可能性があります。__init__これは、パラメータを取らない場合でも当てはまります。これは、コンパイラが基本クラスのコンストラクターを暗黙的に呼び出す他の言語とは異なります。Pythonはそれをしません!

基本クラスを常に呼び出す主な理由_init__は、通常、基本クラスがメンバー変数を作成し、それらをデフォルトに初期化する可能性があるためです。したがって、基本クラスの init を呼び出さないと、そのコードは実行されず、メンバー変数を持たない基本クラスになってしまいます。

class Base:
  def __init__(self):
    print('base init')

class Derived1(Base):
  def __init__(self):
    print('derived1 init')

class Derived2(Base):
  def __init__(self):
    super(Derived2, self).__init__()
    print('derived2 init')

print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

これは印刷されます..

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

このコードを実行します

于 2019-04-19T23:26:31.793 に答える