144

私が尋ねようとしている質問は、Pythonでの__new__と__init__の使用の複製のようです。、しかし、それにもかかわらず、との実際的な違いが正確に何であるかはまだ私にはわかりませ__new____init__

__new__これはオブジェクトの作成用であり、オブジェクトの初期化用であると急いで言う前に__init__、はっきりさせておきます。わかりました。 実際、私はC ++の経験があり、オブジェクトの割り当てと初期化を同様に分離する 新しい配置を使用しているため、この区別は非常に自然です。

Python C APIチュートリアルでは、次のように説明しています。

新しいメンバーは、そのタイプのオブジェクトを(初期化するのではなく)作成する責任があります。メソッドとしてPythonで公開されてい__new__()ます。... 新しいメソッドを実装する理由の1つは、インスタンス変数の初期値を保証することです

だから、ええ-私何をするのかわかります__new__が、それにもかかわらず、Pythonでなぜそれが役立つのかまだわかりません。与えられた例は、__new__「インスタンス変数の初期値を保証したい」場合に役立つかもしれないと言っています。まあ、それは正確に何__init__をするのではないですか?

__new__C APIチュートリアルでは、新しいタイプ(「Noddy」と呼ばれる)が作成され、タイプの関数が定義されている例が示されています。Noddyタイプには、という文字列メンバーが含まれておりfirst、この文字列メンバーは次のように空の文字列に初期化されます。

static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    .....

    self->first = PyString_FromString("");
    if (self->first == NULL)
    {
       Py_DECREF(self);
       return NULL;
    }

    .....
}

__new__ここで定義されたメソッドがなければPyType_GenericNew、すべてのインスタンス変数メンバーをNULLに初期化するだけのを使用する必要があることに注意してください。したがって、このメソッドの唯一の利点は__new__、インスタンス変数がNULLではなく空の文字列として開始されることです。 しかし、インスタンス変数がデフォルト値に初期化されていることを確認する必要がある場合は、メソッドでそれを実行できたはずなので、これが便利なのはなぜですか?__init__

4

6 に答える 6

150

違いは主に、可変型と不変型で発生します。

__new__最初の引数として型を受け入れ、(通常) その型の新しいインスタンスを返します。したがって、可変型と不変型の両方での使用に適しています。

__init__インスタンスを最初の引数として受け入れ、そのインスタンスの属性を変更します。を呼び出して作成後に変更できるようになるため、これは不変型には不適切ですobj.__init__(*args)

と の動作を比較しtupleますlist

>>> x = (1, 2)
>>> x
(1, 2)
>>> x.__init__([3, 4])
>>> x # tuple.__init__ does nothing
(1, 2)
>>> y = [1, 2]
>>> y
[1, 2]
>>> y.__init__([3, 4])
>>> y # list.__init__ reinitialises the object
[3, 4]

それらが分離されている理由について (単純な歴史的な理由は別として):__new__メソッドを正しく処理するには、多数のボイラープレートが必要です (最初のオブジェクトの作成と、最後にオブジェクトを返すことを忘れないでください)。__init__対照的に、メソッドは、設定する必要のある属性を設定するだけなので、非常に単純です。

メソッド__init__の記述が容易になること、および上記の可変と不変の区別に加えて__init__、絶対に必要なインスタンスの不変条件を__new__. ただし、これは一般的に疑わしい方法です。通常は__init__、必要に応じて親クラスのメソッドを呼び出す方が明確です。

于 2011-02-01T05:16:27.620 に答える
45

おそらく他の用途もありますが、__new__本当に明白な用途が1つあります。を使用せずに不変型をサブクラス化することはできません__new__。たとえば、0から。までの整数値のみを含むことができるタプルのサブクラスを作成したいとしますsize

class ModularTuple(tuple):
    def __new__(cls, tup, size=100):
        tup = (int(x) % size for x in tup)
        return super(ModularTuple, cls).__new__(cls, tup)

でこれを行うことはできません。で__init__変更しようとするself__init__、インタプリタは不変オブジェクトを変更しようとしていると文句を言います。

于 2011-02-01T06:00:22.670 に答える
42

__new__()バインド先のクラス以外の型のオブジェクトを返すことができます。__init__()クラスの既存のインスタンスのみを初期化します。

>>> class C(object):
...   def __new__(cls):
...     return 5
...
>>> c = C()
>>> print type(c)
<type 'int'>
>>> print c
5
于 2011-02-01T05:12:44.317 に答える
15

完全な答えではありませんが、おそらく違いを示すものです。

__new__オブジェクトを作成する必要がある場合は常に呼び出されます。__init__呼ばれない状況もあります。1 つの例として、pickle ファイルからオブジェクトを unpickle すると、オブジェクトは割り当てられますが ( __new__)、初期化されません ( __init__)。

于 2011-02-28T14:15:48.903 に答える
0

の特定の用途の 1 つ__new__は、クラスをシングルトンにすることです。

class SingletonClass(object):
  def __new__(cls):
    if not hasattr(cls, 'instance'):
      cls.instance = super(SingletonClass, cls).__new__(cls)
    return cls.instance 

(ソース: Python のシングルトン パターン - 完全ガイド - GeeksforGeeks )

于 2021-04-07T12:09:53.447 に答える