[英]Why is __init__ not called after __new__ SOMETIMES
让我从这开始不重复为什么__init__如果没有args调用__new__就不会被调用 。 我试图为__new__
和__init__
仔细构建一些示例代码, __new__
我找不到任何解释。
基本参数:
__init__
方法,该方法又调用_parse
方法 _parse
方法 super
来避免Python日志记录中的问题:为什么__init__被调用两次? 无论如何, __init__
应该在__new__
之后被调用,并且对于为什么下面的一些样本__new__
的每一个解释我似乎能够指出其他__new__
情况并排除解释。
class NotMine(object):
def __init__(self, *args, **kwargs):
print "NotMine __init__"
self._parse()
def _parse(self):
print "NotMine _parse"
class ABC(NotMine):
def __new__(cls,name,*args, **kwargs):
print "-"*80
print "Entered through the front door ABC.__new__(%s,%s,*%s,**%s)"%(cls,name,args,kwargs)
if name == 'AA':
obj = super(NotMine,ABC).__new__(AA,*args,**kwargs)
print "Exiting door number 1 with an instance of: %s"%type(obj)
return obj
elif name == 'BB':
obj = super(NotMine,ABC).__new__(BB,*args,**kwargs)
print "Exiting door number 2 with an instance of: %s"%type(obj)
return obj
else:
obj = super(NotMine,ABC).__new__(cls,*args,**kwargs)
print "Exiting door number 3 with an instance of: %s"%type(obj)
return obj
class AA(ABC):
def _parse(self):
print "AA _parse"
class BB(ABC):
def __init__(self, *args, **kw):
print "BB_init:*%s, **%s"%(args,kw)
super(BB,self).__init__(self,*args,**kw)
def _parse(self):
print "BB _parse"
class CCC(AA):
def _parse(self):
print "CCCC _parse"
print("########### Starting with ABC always calls __init__ ############")
ABC("AA") # case 1
ABC("BB") # case 2
ABC("NOT_AA_OR_BB") # case 3
print("########### These also all call __init__ ############")
AA("AA") # case 4
BB("BB") # case 5
AA("NOT_AA_OR_BB") # case 6
BB("NOT_AA_OR_BB") # case 7
CCC("ANYTHING") # case 8
print("########### WHY DO THESE NOT CALL __init__ ############")
AA("BB") # case 9
BB("AA") # case 10
CCC("BB") # case 11
如果你执行代码,你可以看到每次调用__new__
它都会宣告它正在退出的“哪个门”和什么类型。 我可以使用相同的“类型”对象退出相同的“门”,并在一个案例中调用__init__
而不是另一个案例。 我已经查看了“调用”类的mro,因为我可以调用该类(或者像CCC中的子主体)并调用__init__
,所以没有提供任何见解。
完备注:本NotMine
我使用图书馆是元史 MarkupTemplate并没有使用厂设计方法的原因是,他们的TemplateLoader需要defaultClass建设。 直到我开始解析才知道,我在__new__
做了。 genshi加载器和模板有很多很酷的伏都魔法,这使得这个值得付出努力。
我可以运行一个未经修改的加载器实例,只要我只通过ABC(抽象工厂排序)类作为默认值,一切都可以正常工作。 事情进展顺利,但这种无法解释的行为后来几乎是一定的错误。
更新: Ignacio,固定顶线问题,如果返回的对象不是“ cls的实例”,则不调用__init__
。 我确实发现调用“构造函数”(例如AA(args..)
是错误的,因为它会再次调用__new__
并且你回到你开始的地方。你可以修改一个arg以采取不同的路径。这只是意味着你调用ABC.__new__
两次而不是无限制。一个有效的解决方案是将class ABC
编辑为:
class ABC(NotMine):
def __new__(cls,name,*args, **kwargs):
print "-"*80
print "Entered through the front door ABC.__new__(%s,%s,*%s,**%s)"%(cls,name,args,kwargs)
if name == 'AA':
obj = super(NotMine,ABC).__new__(AA,*args,**kwargs)
print "Exiting door number 1 with an instance of: %s"%type(obj)
elif name == 'BB':
obj = super(NotMine,ABC).__new__(BB,*args,**kwargs)
print "Exiting door number 2 with an instance of: %s"%type(obj)
elif name == 'CCC':
obj = super(NotMine,ABC).__new__(CCC,*args,**kwargs)
print "Exiting door number 3 with an instance of: %s"%type(obj)
else:
obj = super(NotMine,ABC).__new__(cls,*args,**kwargs)
print "Exiting door number 4 with an instance of: %s"%type(obj)
## Addition to decide who calls __init__ ##
if isinstance(obj,cls):
print "this IS an instance of %s So call your own dam __init__"%cls
return obj
print "this is NOT an instance of %s So __new__ will call __init__ for you"%cls
obj.__init__(name,*args, **kwargs)
return obj
print("########### now, these DO CALL __init__ ############")
AA("BB") # case 9
BB("AA") # case 10
CCC("BB") # case 11
注意最后几行。 不调用__init__
如果它是一个“不同的”类对我来说没有意义,特别是当“不同”类仍然是调用__init__
的类的子类时。 我不喜欢上面的编辑,但现在我的规则变得更好了。
从文档 :
如果
__new__()
没有返回cls的实例,则不会调用新实例的__init__()
方法。
这是为了允许__new__()
返回另一个类的新实例,该实例有自己的__init__()
来代替。 您需要检测是否正在创建新的cls,如果没有,则调用相应的构造函数。
这只是我的两分钱,但你为什么不使用Python鸭子打字为Genshi提供类似于类的东西?
我快速浏览了Genshi 源代码 ,我在TemplateLoader的'class'参数中看到的唯一要求是它可以使用给定的参数调用。
我认为用工厂函数模拟一个返回实际创建实例的类会更容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.