2012-07-24 7 views
11

私は特定の__init__()が設定されているクラスインスタンスを返すために、クラスのメソッド__new__()をオーバーライドしています。Pythonはインスタンス作成時にインスタンスメソッド__init __()を呼び出さないのに対し、クラス提供の__init __()を代わりに呼び出すのはなぜですか?

典型的な実装では、クラスの新しいインスタンスを作成します。

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

でPythonドキュメントは言うものの、Pythonは、代わりにインスタンス固有のメソッドのクラスが提供する__init__()メソッドを呼び出しているようですsuper(currentclass、cls).__ new __(cls [、...]) を適切な引数で使用して、 スーパークラスの__new __()自己が新しいインスタンスであり、 残りの引数は

__newは__()CLSのインスタンスを返す場合、新しいインスタンスの__init __()メソッド は__init __のように呼び出されます(自己[、...])、 __new __()と同じものが渡されました。 myinit()を実行するために取得する唯一の方法だmyclass.__init__()内部self.__init__()として明示的にそれを呼び出すことです

#!/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 = {} 

を出力します

は、ここに私のテストコードです。

+1

グレート質問:この動作は、次のコードは、(旧スタイルのクラスと同等の例とは異なり)例外が発生した理由です! – Marcin

答えて

8

特別な方法を見ていますインスタンスのタイプではなく、インスタンス自体に依存します。これはdocumented behaviourです:

新しいスタイルのクラスでは

、特殊な方法の暗黙の呼び出しは唯一のオブジェクトの型に定義されている場合ではないオブジェクトのインスタンス辞書に、正しく動作することが保証されています。

>>> 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() 
8

__init__を含むだけでなく、__add__ようなオペレータのオーバーロード、等)の様々な特別な方法がalways accessed via the class rather than the instanceです。それだけでなく、クラスまたはメタクラスで__getattr__または__getattribute__メソッドを使用してアクセスすることはできません。クラスに直接アクセスする必要があります。この方法で__getattribute__()機械をバイパス

は特別な方法の処理にある程度の柔軟性を犠牲にし、インタプリタ内の速度の最適化のための有意な範囲を提供する(特別な方法がオンに設定されなければならない:これは、効率の理由のためでありますインタプリタによって一貫して呼び出されるためには、クラスオブジェクト自体)。

それはあなたが達成しようとしているものを完全には明らかではないのですが、あなたはここで何ができる一つのことは__new__メソッド内myclassをサブクラス化することです:新しいスタイルのクラスの

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) 
関連する問題