让我从这不是重复
为什么 __init__ 不被调用 if __new__ 调用没有 args。我试图仔细构建一些示例代码,__new__
但__init__
我找不到任何解释。
基本参数:
- 有一个名为 NotMine 的基类,因为它来自另一个库(我会在最后披露,这里不重要)
- 该类有一个
__init__
方法,该方法又调用一个_parse
方法 - 我需要覆盖
_parse
子类中的方法 - 在调用之前我不知道我正在创建哪个子类
- 我知道有工厂设计方法,但我不能在这里使用它们(更多在最后)
- 我试图小心使用
super
以避免 Python 日志记录中的问题:为什么 __init__ 被调用两次? - 我知道这也是“一种” AbstractBaseMehtod 机会,但这并没有帮助
无论如何,__init__
应该在__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
我使用
的库是Genshi 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__
。我不喜欢上面的编辑,但至少我现在得到的规则好一点。