在__new__构造函数中替换已创建对象的__init__
问题描述:
我试图替换派生类的__init__
方法。 但由于某种原因,原来的__init__
被调用,虽然__dict__
显示替换函数。 如果我手动调用__init__
,替换函数调用... 示例代码:在__new__构造函数中替换已创建对象的__init__
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__
被称为(以及如何避免那),还是另一种解决问题的方式?
答
像所有神奇的方法一样,__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...
感谢您的提示,但我已经试过了。它不适用于第二个继承。第一个或第二个继承类无法按预期工作(有时会将这两个级别实例化)。 –
@AlexG。看看上面的内容;那是你在追求什么? – ecatmur
再次感谢,它看起来不错,但我得到了“最大递归RuntimeError”,因为派生的__init__调用了它们的超级__init__ –