为什么__init__在__new__之后没有被调用有时

问题描述:

让我从这开始不是重复的 Why does __init__ not get called if __new__ called with no args。我试图仔细地构建一些__new____init__的示例代码,我没有找到解释。为什么__init__在__new__之后没有被调用有时

基本参数:

  • 有一个叫NotMine因为它从另一个库基类(我将在月底公布,在这里并不重要)
  • 那类有一个__init__方法随后调用_parse方法
  • 我需要重写在子类中的方法_parse
  • 其子类我创建不知道,直到调用
  • 我知道有工厂的设计方法,但我不能(在末尾更多)在这里使用它们
  • 我曾试图弥补谨慎使用super避免问题 Python logging: Why is __init__ called twice?
  • 我知道这也是“之类的“一个AbstractBaseMehtod机会,但没有帮助__new__后和为什么一些样品下面不工作我似乎能够指向做工作,其他情况下每解释

反正__init__应该叫和排除解释。

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(抽象工厂类)作为默认类传递即可。事情运作良好,但这种无法解释的行为后来几乎是某种错误。

UPDATE: 伊格纳西奥,钉顶线问题,如果返回的对象不是一个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__的类的子类时。我不喜欢上面的编辑,但现在我得到的规则好一点。

+0

Genshi是否使用元类?请参阅http://*.com/questions/100003/what-is-a-metaclass-in-python – Borealid 2012-02-20 19:25:27

+0

不,我的示例代码不使用genshi作为基础。 – 2012-02-20 19:32:21

the documentation

如果__new__()不返回CLS一个实例,则新实例的方法__init__()不会被调用。

这是为了让__new__()return a new instance of a different class,它有自己的__init__()被改为调用。你需要检测你是否创建了一个新的cls,如果没有,就调用相应的构造函数。

+0

好吧,我有种超级文字“不返回cls的实例”。但是,我返回一个不同类的新实例,它有自己的'__init__',但它不会被调用,即使它是一个常见的基础(在旧的mro中)。我**我应该称它为新? – 2012-02-20 19:46:43

+0

你应该通过调用它的构造函数在'__new __()'中实例化它。 – 2012-02-20 19:48:19

+0

哎。坏主意在这里。我认为这可能会导致上面引用的“两次调用”问题,但由于ABC是一个通用基础,因此在代码中调用构造函数会导致对__new__的递归调用并挂起会话:-( – 2012-02-20 20:00:02

我的两毛钱就在这里,但为什么不用Python鸭子打字给Genshi提供像课堂上的东西呢?

我对Genshi source code进行了简单的介绍,我在TemplateLoader的'class'参数上看到的唯一要求是它可以用给定的参数调用。

我认为用工厂函数模拟一个类返回实际创建的实例会更容易。

+0

是的,深入源代码它最终调用构造函数在default_class上可以是任何可调用的。我认为这将是一个可行的选择。未来可能会有所不同,它似乎“传递MarkupTemplate的子类是正确的OO事情”。但是,对我来说,“__new__”应该有不同的表现,所以我可以说些什么;-) – 2012-02-20 23:00:25