2012-02-20 6 views
8

के बाद क्यों नहीं बुलाया जाता है, मुझे इसके साथ शुरू करने दें Why does __init__ not get called if __new__ called with no args का दोहराव नहीं है। मैंने __new__ और __init__ के लिए कुछ नमूना कोड सावधानीपूर्वक बनाने की कोशिश की है जिसमें मुझे कोई स्पष्टीकरण नहीं मिल रहा है।__nit__ को __new__ SOMETIMES

बुनियादी मानकों:

  • एक आधार वर्ग 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__ एक मामले में बुलाया गया है, न कि दूसरे। मैंने "कॉलिंग" वर्ग के एमआरओ को देखा है और यह कोई अंतर्दृष्टि प्रदान नहीं करता है क्योंकि मैं उस वर्ग (या सीसीसी में एक उप-वर्ग) का आह्वान कर सकता हूं और __init__ कहलाता है।

समाप्ति नोट्स: मैं उपयोग कर रहा हूँ NotMine पुस्तकालय Genshi MarkupTemplate और एक फैक्टरी डिजाइन विधि का उपयोग नहीं करने के लिए कारण है उनके TemplateLoader एक defaultClass की जरूरत है कि निर्माण करने के लिए है। मैं तब तक नहीं जानता जब तक कि मैं पार्सिंग शुरू नहीं करता, जो मैं __new__ में करता हूं। वहां बहुत अच्छा वूडू जादू है जो गेन्सी लोडर और टेम्पलेट्स करते हैं जो इस प्रयास को लायक बनाते हैं।

मैं अपने लोडर का एक असम्बद्ध उदाहरण चला सकता हूं और वर्तमान में जब तक मैं केवल एबीसी (अमूर्त सॉर्ट-ऑफ-फैक्ट्री) कक्षा को डिफ़ॉल्ट रूप से पास नहीं करता तब तक सब कुछ काम करता है। चीजें अच्छी तरह से काम कर रही हैं लेकिन बाद में यह अस्पष्ट व्यवहार लगभग एक निश्चित बग है।

अद्यतन: इग्नेसियो,, शीर्ष पंक्ति सवाल किसी न किसी अगर लौटे वस्तु cls तो __init__ नहीं बुलाया जाता है एक "के कहने" नहीं है। मुझे लगता है कि "कन्स्ट्रक्टर" को कॉल करना (उदाहरण के लिए AA(args..) गलत है क्योंकि यह __new__ को फिर से कॉल करेगा और आप ठीक कहां से शुरू कर चुके हैं। आप एक अलग पथ लेने के लिए एक तर्क संशोधित कर सकते हैं। इसका मतलब है कि आप 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

क्या गैन्शी मेटाक्लास का उपयोग कर रहा है? Http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python – Borealid

+0

नहीं, मेरा नमूना कोड आधार के रूप में genshi का उपयोग नहीं करता है। –

उत्तर

7

the documentation से:

तो __new__()cls का एक उदाहरण वापस नहीं करता है, तो नया उदाहरण के __init__() विधि लागू नहीं किया जाएगा।

यह जो अपनी ही __init__() है बजाय नाम से जाना, return a new instance of a different class को __new__() अनुमति है। आपको यह पता लगाने की आवश्यकता होगी कि क्या आप एक नया सीएल बना रहे हैं, और अगर नहीं तो उचित कन्स्ट्रक्टर को कॉल करें।

+0

ठीक है, मुझे सुपर शाब्दिक मिलता है "सीएलएस का उदाहरण वापस नहीं करता है"। लेकिन, मैं एक अलग वर्ग का एक नया उदाहरण लौटा रहा हूं, जिसमें इसका अपना '__init__' है लेकिन इसे कॉल नहीं किया जाता है, भले ही यह एक सामान्य आधार (पुराने एमआरओ में) हो। मैं ** मैं ** इसे नए में कॉल करना चाहता हूं ?? –

+0

आपको इसे अपने कन्स्ट्रक्टर को कॉल करके * __new __() 'में तत्काल * करना है। –

+0

आउच। यहाँ बुरा विचार है। मैंने सोचा कि इससे ऊपर उद्धृत "दो बार बुलाया गया" समस्या हो सकती है, लेकिन चूंकि एबीसी एक आम आधार है, इसलिए कोड में कन्स्ट्रक्टर को कॉल करने से 'रिक्त कॉल' को '__new__' तक पहुंचाया जाता है और सत्र लटकता है :-( –

0

बस मेरे दो सेंट यहाँ हैं, लेकिन आप एक कक्षा की तरह व्यवहार करने वाले कुछ के साथ जेन्शी प्रदान करने के लिए पाइथन डक टाइपिंग का उपयोग क्यों नहीं करते?

मैंने गैन्शी source code पर एक त्वरित नज़र डाली और टेम्पलेटलोडर को 'कक्षा' पैरामीटर पर देखी गई एकमात्र आवश्यकता यह है कि यह दिए गए तर्कों के साथ कॉल करने योग्य है।

मुझे लगता है कि वास्तविक निर्मित उदाहरण को वापस करने वाले फैक्ट्री फ़ंक्शन के साथ कक्षा को नकल करना आसान होगा।

+0

हां, स्रोत में गहराई से यह अंततः निर्माता को बुलाता है default_class पर जो किसी भी कॉल करने योग्य हो सकता है। मुझे लगता है कि यह एक व्यवहार्य विकल्प होगा। भविष्य अलग हो सकता है और यह "ऐसा लगता है" कि मार्कअप टेम्पलेट के उप-वर्ग को पार करना सही ओओ चीज है। लेकिन फिर से यह मुझे "लग रहा था" कि '__new__' अलग तरीके से व्यवहार करना चाहिए था इसलिए मैं कौन बात करूँगा ;-) –

संबंधित मुद्दे