14

特定のセット__new__()を持つクラスインスタンスを返すために、クラスのメソッドを上書きしています。Pythonは、インスタンス固有のメソッドではなく__init__()、クラス提供のメソッドを呼び出しているようですが、Pythonのドキュメントは__init__()

http://docs.python.org/reference/datamodel.html

言う:

一般的な実装では、super(currentclass、cls).__ new __(cls [、...])を適切な引数で使用してスーパークラスの__new __()メソッドを呼び出し、必要に応じて新しく作成されたインスタンスを変更してから、クラスの新しいインスタンスを作成します。それ。

__new __()がclsのインスタンスを返す場合、新しいインスタンスの__init __()メソッドは__init __(self [、...])のように呼び出されます。ここで、selfは新しいインスタンスであり、残りの引数はに渡されたものと同じです。 __新着__()。

これが私のテストコードです:

#!/usr/bin/env python

import new

def myinit(self, *args, **kwargs):
    print "myinit called, args = %s, kwargs = %s" % (args, kwargs)


class myclass(object):
    def __new__(cls, *args, **kwargs):
        ret = object.__new__(cls)

        ret.__init__ = new.instancemethod(myinit, ret, cls)
        return ret

    def __init__(self, *args, **kwargs):
        print "myclass.__init__ called, self.__init__ is %s" % self.__init__
        self.__init__(*args, **kwargs)

a = myclass()

どの出力

$ python --version
Python 2.6.6
$ ./mytest.py
myclass.__init__ called, self.__init__ is <bound method myclass.myinit of <__main__.myclass object at 0x7fa72155c790>>
myinit called, args = (), kwargs = {}

実行する唯一の方法は、 insidemyinit()として明示的に呼び出すことです。self.__init__()myclass.__init__()

4

3 に答える 3

11

新しいスタイルのクラスの特別なメソッドは、インスタンス自体ではなく、インスタンスの型で検索されます。これは文書化された動作です:

新しいスタイルのクラスの場合、特別なメソッドの暗黙的な呼び出しは、オブジェクトのインスタンス ディクショナリではなく、オブジェクトの型で定義されている場合にのみ正しく機能することが保証されます。その動作が、次のコードが例外を発生させる理由です (古いスタイルのクラスの同等の例とは異なります)。

>>> class C(object):
...     pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()
于 2012-07-24T16:45:14.357 に答える
8

さまざまな特殊メソッド (__init__だけでなく、 などの演算子のオーバーロードも含む__add__) は、常にインスタンスではなくクラスを介してアクセスされます。それだけでなく、クラスまたはメタクラスの__getattr__or__getattribute__メソッドを介してアクセスすることはできません。クラスに直接存在する必要があります。これは効率上の理由によるものです。

この方法で機構をバイパスする__getattribute__()と、インタープリター内で速度を最適化するための大きな範囲が提供されますが、特別なメソッドの処理の柔軟性がいくらか犠牲になります (インタープリターによって一貫して呼び出されるためには、クラス オブジェクト自体に特別なメソッドを設定する必要があります)。 .

何を達成しようとしているのかは完全には明らかではありませんが、ここでできることの 1 つは、メソッドmyclass内でサブクラス化することです。__new__

class myclass(object):
    def __new__(cls, *args, **kwargs):
        class subcls(cls):
            def __new__(cls, *args, **kwargs):
                return object.__new__(cls)
        subcls.__init__ = myinit
        return subcls(*args, **kwargs)
于 2012-07-24T16:45:03.987 に答える