2012-02-20 90 views
8

讓我從這開始不是重複的 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://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Borealid 2012-02-20 19:25:27

+0

不,我的示例代碼不使用genshi作爲基礎。 – 2012-02-20 19:32:21

回答

7

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

0

我的兩毛錢就在這裏,但爲什麼不用Python鴨子打字給Genshi提供像課堂上的東西呢?

我對Genshi source code進行了簡單的介紹,我在TemplateLoader的'class'參數上看到的唯一要求是它可以用給定的參數調用。

我認爲用工廠函數模擬一個類返回實際創建的實例會更容易。

+0

是的,深入源代碼它最終調用構造函數在default_class上可以是任何可調用的。我認爲這將是一個可行的選擇。未來可能會有所不同,它似乎「傳遞MarkupTemplate的子類是正確的OO事情」。但是,對我來說,「__new__」應該有不同的表現,所以我可以說些什麼;-) – 2012-02-20 23:00:25

相關問題