2012-01-18 16 views
14

किसी बिल्टिन प्रकार के साथ-साथ किसी अन्य वर्ग से प्राप्त होने पर, ऐसा लगता है कि बिल्टिन प्रकार का कन्स्ट्रक्टर सुपर क्लास कन्स्ट्रक्टर को कॉल नहीं करता है। इसके परिणामस्वरूप __init__ विधियों को एमआरओ में बिल्टिन के बाद आने वाले प्रकारों के लिए बुलाया नहीं जा रहा है।पायथन 3 बिल्टिन प्रकार __init__ सुपर() .__ init__ को कॉल नहीं करता है?

उदाहरण:

class A: 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     print("A().__init__()") 

class B(list, A): 
    def __init__(self, *args, **kwargs): 
     print("B().__init__() start") 
     super().__init__(*args, **kwargs) 
     print("B().__init__() end") 

if __name__ == '__main__': 
    b = B() 

इस नमूने में, एक .__ init__ कभी नहीं कहा जाता है। जब बी को class B(A, list) के रूप में परिभाषित किया जाता है - विरासत आदेश को स्विच करना - यह इच्छित के रूप में कार्य करता है (यानी ए .__ init__ कहा जाता है)।

विरासत आदेश पर यह बहुत ही सूक्ष्म निर्भरता बल्कि गैर-पायथनिक लगता है, क्या इसका इरादा इस तरह से किया गया है? इसका मतलब यह भी है कि आपको कभी भी जटिल श्रेणी पदानुक्रमों में बिल्टिन प्रकारों से प्राप्त नहीं होना चाहिए, क्योंकि आप यह नहीं जान सकते कि एमआरओ में बिल्टिन कहां समाप्त होता है जब कोई और आपके वर्गों (रखरखाव डरावनी) से निकलता है। क्या मैं कुछ भूल रहा हूँ?

अतिरिक्त जानकारी: अजगर संस्करण 3,1

+0

अजगर कभी नहीं सुपर क्लास की '__init__' तरीकों – Marcin

+2

क्या इसके साथ init__'' एक .__ कहेंगे स्वचालित मंगलाचरण किया गया है? 'list .__ init__' एक तर्क लेता है, और अगर यह और भी हो जाता है तो एक त्रुटि फेंकता है। यहां तक ​​कि अगर यह अन्य तर्कों को मनमाने ढंग से स्वीकार करता है, तो यह पहले व्यक्ति को बंद कर देगा, इसलिए ए देखा गया विरासत आदेश पर निर्भर करेगा। –

+0

एक समान प्रश्न: http: // stackoverflow।कॉम/प्रश्न/3277367/कैसे-करता-पायथन-सुपर-वर्क-एकाधिक-विरासत के साथ Guido के उस प्रश्न के उत्तर से आने के साथ: http://python-history.blogspot.com/2010/06/method- रेज़ोल्यूशन-ऑर्डर.html – aganders3

उत्तर

9

super() का सही उपयोग नहीं बल्कि सूक्ष्म है और कुछ देखभाल की आवश्यकता होती है, तो सहयोग के तरीकों में एक ही हस्ताक्षर नहीं सब है।

class A(object): 
    def __init__(self, param_a, **kwargs): 
     self.param_a = param_a 
     super(A, self).__init__(**kwargs) 

class B(A): 
    def __init__(self, param_b, **kwargs): 
     self.param_b = param_b 
     super(B, self).__init__(**kwargs) 

class C(A): 
    def __init__(self, param_c, **kwargs): 
     self.param_c = param_c 
     super(C, self).__init__(**kwargs) 

class D(B, C): 
    def __init__(self, param_d, **kwargs): 
     self.param_d = param_d 
     super(D, self).__init__(**kwargs) 

d = D(param_a=1, param_b=2, param_c=3, param_d=4) 

नोट यह जरूरी है कि कि सभी तरीकों सहयोग करने और यह सुनिश्चित करें कि सभी तरीकों कुछ हद तक एक संगत हस्ताक्षर की जरूरत है यह, जिसके आधार पर विधि कहा जाता है कोई फर्क नहीं पड़ता: __init__() तरीकों के लिए हमेशा की तरह पैटर्न इस प्रकार है।

अंतर्निहित प्रकार के रचनाकारों में कन्स्ट्रक्टर हस्ताक्षर नहीं हैं जो इस तरह के सहयोग में भाग लेने की अनुमति देते हैं। भले ही उन्होंने super().__init__() पर कॉल किया हो, फिर भी यह तब तक बेकार होगा जब तक कि सभी कन्स्ट्रक्टर हस्ताक्षर एकीकृत नहीं होते। तो अंत में आप सही हैं - वे सहयोगी कन्स्ट्रक्टर कॉल में कण के लिए उपयुक्त नहीं हैं।

super() केवल तभी उपयोग किया जा सकता है जब सभी सहयोगी विधियों के समान हस्ताक्षर होते हैं (जैसे __setattr__()) या यदि आप ऊपर (या समान) पैटर्न का उपयोग करते हैं। super() का उपयोग बेस क्लास विधियों को कॉल करने का एकमात्र पैटर्न नहीं है, हालांकि। यदि आपके एकाधिक विरासत पैटर्न में कोई "हीरा" नहीं है, तो आप स्पष्ट बेस क्लास कॉल का उपयोग कर सकते हैं, उदाहरण के लिए B.__init__(self, param_a)। कई आधार वर्गों वाले वर्ग बस कई रचनाकारों को कॉल करते हैं। यहां तक ​​कि यदि हीरे हैं, तो भी आप कभी-कभी स्पष्ट कॉल का उपयोग कर सकते हैं, जब तक आप ध्यान दें कि __init__() को नुकसान के बिना कई बार बुलाया जा सकता है।

यदि आप super() का उपयोग ठेकेदारों के लिए किसी भी तरह से करना चाहते हैं, तो आपको वास्तव में कई अंतर्निहित पदानुक्रमों में अंतर्निर्मित प्रकारों (object को छोड़कर) के उप-वर्गों का उपयोग नहीं करना चाहिए। कुछ आगे पढ़ने:

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