2016-06-28 14 views
1

派生クラスの__init__メソッドを置き換えようとしています。 何らかの理由で、元の__init__が呼び出されますが、__dict__には置き換えられた機能が示されています。 私は手動で__init__を呼び出した場合、置き換え機能が... 例コードと呼ばれる:作成したオブジェクトの__init__を__new__コンストラクタに置き換えます。

class TheBase(object): 

    def __new__(cls, *args, **kwargs): 
     newInstance = super(TheBase, cls).__new__(cls) 

     newInstance._origInit = newInstance.__init__ 
     newInstance.__init__ = newInstance._myInit 
     print "Replaced the init of {} with {} ({})".format(newInstance, newInstance._myInit, id(newInstance._myInit)) 
     print newInstance.__dict__ 
     return newInstance 

    def _myInit(self, *args, **kwargs): 
     print "TheBase _myInit of {} ({})".format(self, id(self.__init__)) 
     self._origInit(*args, **kwargs) 
     self._afterInit() 

    def _afterInit(self): 
     print "Init has passed..." 
     # Do some magic here... 


class MyDerived(TheBase): 
    def __init__(self, great=False): 
     TheBase.__init__(self) 
     print "MyDerived __init__ of {} ({})".format(self, id(self.__init__)) 


class MyDerived2(MyDerived): 
    def __init__(self): 
     MyDerived.__init__(self, great=True) 
     print "MyDerived2 __init__ of {} ({})".format(self, id(self.__init__)) 



sd = MyDerived() 

print "--------------- manual init --------------" 
sd.__init__() 

結果:私の本当の世界のプロジェクトで

Replaced the init of <__main__.MyDerived object at 0x00385390> with <bound method MyDerived._myInit of <__main__.MyDerived object at 0x00385390>> (35356224) 
{'__init__': <bound method MyDerived._myInit of <__main__.MyDerived object at 0x00385390>>, '_origInit': <bound method MyDerived.__init__ of <__main__.MyDerived object at 0x00385390>>} 
MyDerived __init__ of <__main__.MyDerived object at 0x00385390> (35213640) 
--------------- manual init -------------- 
TheBase _myInit of <__main__.MyDerived object at 0x00385390> (35213640) 
MyDerived __init__ of <__main__.MyDerived object at 0x00385390> (35213640) 
Init has passed... 

、私は(スレッドを開始したいです基底クラス)が、派生クラスの__init__が終了するまで実行してはなりません。これは一部のリファクタリングの一部であり、既存の派生クラスは他の人が開発しているため、コードを変更することはできません(スレッドを開始することもできません)。時々、派生クラスが再び派生しているため、クラスではなくインスタンスに__init__の交換

は、こともできない(class MyDerived2(MyDerived):

は、元__init__が呼び出される(および回避する方法、なぜ誰もアイデアを持っていますそれ)、または別の方法で問題を解決しますか?

答えて

0

すべてのマジックメソッドと同様に、__init__はインスタンスではなくクラスで検索されます。

マジックメソッドをカスタマイズしたり上書きしたりする場合は、metaclassを使用してください。

例:

class TheMeta(type): 
    def __init__(cls, name, bases, dct): 
     def _myInit(self, *args, **kwargs): 
      if type(self) is cls: 
       print "_myInit of {} {} ({})".format(name, self, id(self.__init__)) 
       cls._origInit(self, *args, **kwargs) 
       cls._afterInit(self) 
      else: 
       cls._origInit(self, *args, **kwargs) 

     def _afterInit(self): 
      print "Init has passed..." 
      # Do some magic here... 

     cls._origInit = cls.__init__ 
     cls.__init__ = _myInit 
     cls._afterInit = _afterInit 
     super(TheMeta, cls).__init__(name, bases, dct) 

class TheBase(object): 
    __metaclass__ = TheMeta 

class MyDerived(TheBase): 
    def __init__(self, great=False): 
     TheBase.__init__(self) 
     print "MyDerived __init__ of {} ({})".format(self, id(self.__init__)) 

class MyDerived2(MyDerived): 
    def __init__(self): 
     MyDerived.__init__(self, great=True) 
     print "MyDerived2 __init__ of {} ({})".format(self, id(self.__init__)) 

sd = MyDerived() 
d2 = MyDerived2() 

出力(online):ヒントの

_myInit of MyDerived <__main__.MyDerived object at 0xb72d97ec> (3075484484) 
MyDerived __init__ of <__main__.MyDerived object at 0xb72d97ec> (3075190908) 
Init has passed... 
_myInit of MyDerived2 <__main__.MyDerived2 object at 0xb72d98ec> (3075484484) 
MyDerived __init__ of <__main__.MyDerived2 object at 0xb72d98ec> (3073212204) 
MyDerived2 __init__ of <__main__.MyDerived2 object at 0xb72d98ec> (3075190908) 
Init has passed... 
+0

おかげで、私はそれを試してみました。 2番目の継承では機能しません。第1または第2の継承クラスは、期待どおりに動作しません(両方のレベルが時々インスタンス化されます)。 –

+0

@AlexG。上記を見てください。あなたが何をしているのですか? – ecatmur

+0

__init__が__init__を呼び出すため、「再帰RuntimeError」が最大になってしまいました。 –

関連する問題