web-dev-qa-db-ja.com

コンストラクタとしての__init__?

Pythonに飛び込む -

これは魅力的ですが、これをクラスのコンストラクターと呼ぶのは正しくありません。それはコンストラクタのように見えるので魅力的です(慣例により、__init__はクラスに定義された最初のメソッドです)、1つのように動作します(クラスの新しく作成されたインスタンスで実行される最初のコードです)、そして1つのようにも聞こえます(「init」は確かにコンストラクターのような性質を示唆しています)。間違っています。オブジェクトは__init__が呼び出されるまでに既に構築されており、クラスの新しいインスタンスへの有効な参照が既にあるためです。

__init__が呼び出されるまでにオブジェクトが既に構築されているため、__init__constructorとして呼び出すことは正しくないことを引用しています。だが! constructorは、インスタンスのデータメンバーを初期化するために本質的に使用されるため、オブジェクトが構築された後にのみ呼び出されるという印象を受けていましたconstructorが呼び出されるまでにオブジェクトが存在しなかった場合、意味がありませんか? (C++/Javaのバックグラウンドから来ています)

39
Vaibhav Bajpai

クラスFooがある場合:

  • Foo()constructorです
  • Foo.__init__()initializerです
  • Foo.__new__() は、アロケーター

Pythonオブジェクトの構築は、単に新しいインスタンスを割り当てた後に、そのインスタンスを初期化することです。

個人的には、「__init__はコンストラクターではありません」ということは、髪の毛を細かく分割するものだと思います。

__init__は、新しいオブジェクトが要求されたときに呼び出されます。オブジェクトの通常の操作に必要な不変条件が設定されるように、引数を使用して新しいオブジェクトに属性を割り当てることになっています。オブジェクトは、__init__のコードが実行を開始するまでに、属性を格納するための有効な既存の場所です。 通常、新しいオブジェクトには、__init__のコードが実行を開始した時点で既に定義されている属性はありません(すべてのオブジェクトが所有するものを除く)。

新しいオブジェクトが要求されると、C++コンストラクターが呼び出されます。オブジェクトの通常の操作に必要な不変条件が設定されるように、引数を使用して新しいオブジェクトのフィールドに割り当てることが想定されています。オブジェクトは、コンストラクターのコードが実行を開始するまでにフィールドを保存するための有効な既存の場所です。 コンストラクター内のコードの実行が開始されると、新しいオブジェクトにはすべての宣言済みフィールドが既にありますが、それらにはゴミが含まれています。

Javaコンストラクターは、新しいオブジェクトが要求されたときに呼び出されます。引数を使用して、新しいオブジェクトのフィールドに割り当て、オブジェクトの通常の操作に必要な不変条件が設定されます。オブジェクトは、コンストラクターのコードが実行を開始するまでにフィールドを格納する有効な既存の場所です。コンストラクターのコードが実行を開始すると、新しいオブジェクトにはすべての宣言済みフィールドがあります。デフォルト値

__init__メソッドとC++/Javaコンストラクターの主な違いは、私が強調した最後の文にあります。これは、Java/C++の静的な性質とPythonの動的な性質の違いにすぎません。同じWordで参照してはならない根本的に異なる概念を呼び出すことを保証するものではないと思います。

Pythonistaが__init__をコンストラクターとして参照したくない主な理由は、C++/Javaコンストラクターの人々thinkが「新しいオブジェクトを作成する」というのは、あなたがそれらを呼び出すときに彼らがするように見えるからです。ただし、コンストラクターを呼び出すと、実際に2つのことが行われます。新しいオブジェクトが作成され、コンストラクターが呼び出されて初期化されます。 C++/Javaでは、「新規オブジェクトの作成」部分は見えませんが、Python(__new__メソッド経由)で公開/カスタマイズできます。

したがって、__init__メソッドの役割はC++/Javaコンストラクターの役割に非常に似ていますが、一部の人々は、「__init__はコンストラクタではありません」。

32
Ben

コンストラクター戻り値インスタンスであり、失敗する可能性があります。だが __init__はインスタンスを返しません。ときでさえ __init__発生および例外、__del__は、インスタンスを削除するために呼び出されます。

これはここで見ることができます:

class A(object):
    def __init__(self):
        raise ValueError

    def __del__(self):
        print "Called"

def main():
    try:
        a = A()
    except ValueError, e:
        print "ValueError"

if __== '__main__':
    main()

__new__一方、インスタンスを返します。

5

http://www.programiz.com/article/python-self-why から

__init__()はコンストラクタではありません

[..] 1つの重要な結論[..]は、__init__()はコンストラクタではないということです。多くの素朴なPythonプログラマーは、オブジェクトを作成するときに__init__()が呼び出されるため、プログラマと混同されます。詳細な検査により、__init__()の最初のパラメーターオブジェクト自体(オブジェクトは既に存在します)関数__init__()は、オブジェクトが作成された直後に呼び出され、オブジェクトの初期化に使用されます。

技術的に言えば、コンストラクターはオブジェクト自体を作成するメソッドです。 Pythonでは、このメソッドは__new__()です。このメソッドの一般的な署名は

__new__(cls, *args, **kwargs)

ベンから与えられた回答に関して、私はここで、ほとんどの言語はその定義に従っていないと主張します(完全に)。

さらに:

__new__()が呼び出されると、クラス自体が最初の引数として自動的に渡されます。これが、上記の署名のclsの目的です。繰り返しますが、selfと同様に、clsは単なる命名規則です。さらに、_*args_および_**kwargs_は、Pythonのメソッド呼び出し中に任意の数の引数を取得するために使用されます。

__new__()を実装する際に覚えておくべき重要なことは次のとおりです。

  1. __new__()は常に__init__()の前に呼び出されます。
  2. 最初の引数は、暗黙的に渡されるクラス自体です。
  3. __new__()から常に有効なオブジェクトを返します。必須ではありませんが、それがポイントです。

ボトムライン(私にとって):__new__()は、__init__()ではなく、コンストラクターのように見えますが、すべての実用的な手段で、__init__()は、ほとんどの人がコンストラクターが考えるものの一部です行う。

2
Marc

John Zelleの「Programming Python:Introduction to Computer Science」では、「特別な方法__init__はオブジェクトコンストラクターです。 Pythonはこのメソッドを呼び出して新しいオブジェクトを初期化します。__init__は、オブジェクトのインスタンス変数の初期値を提供することです。」

0
fkkcloud