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

Phi*_*per 10 python genshi

让我从这开始不重复 为什么__init__如果没有args调用__new__就不会被调用.我试图精心构建了一些示例代码__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
Run Code Online (Sandbox Code Playgroud)

如果您执行代码,您可以看到每次调用__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
Run Code Online (Sandbox Code Playgroud)

注意最后几行.不调用__init__它是否是一个"不同"的类对我来说没有意义,特别是当"不同"类仍然是类调用的子类时__init__.我不喜欢上面的编辑,但现在我的规则变得更好了.

Ign*_*ams 10

文档:

如果__new__()不返回cls的实例,则__init__()不会调用新实例的方法.

这是为了让__new__()返回的新实例不同的,它有自己的__init__()被改为调用.您需要检测是否正在创建新的cls,如果没有,则调用相应的构造函数.