दिलचस्प पोस्ट
जावा एरे अजीब संख्याओं को छपाई, और पाठ OpenSSL EVP_BytesToKey विधि का सी # संस्करण? SHA1 बनाम एमडी 5 बनाम SHA256: जो एक PHP लॉगिन के लिए उपयोग करना है? पायथन इंटरप्रेटर में एक अद्यतन पैकेज कैसे पुनः आयात करें? पारदर्शी आधा चक्र एक div से बाहर काट दिया Base64 के साथ एक पायथन स्ट्रिंग को एन्कोड करने के लिए मुझे 'बी' की आवश्यकता क्यों है? अजगर-स्क्रैपर का उपयोग करके गतिशील सामग्री को खरोंच करना क्या आप कुछ उदाहरण प्रदान कर सकते हैं कि क्यों regex के साथ एक्सएमएल और एचटीएमएल को पार्स करना मुश्किल है? जावा कक्षापथ में एक निर्देशिका में सभी जार भी शामिल है कैसे एक dmg मैक ओएस एक्स फाइल बनाने के लिए (एक गैर-मैक मंच पर)? कैसे सी # में एक फ़ाइल को पढ़ने और लिखने के लिए "परतें" और "टायर्स" के बीच अंतर क्या है? मैं सर्वर साइड पर वेबसॉकेट संदेश कैसे भेज और प्राप्त कर सकता हूं? सफाई उपयोगकर्ता पासवर्ड JQuery का उपयोग कर फ़ाइल डाउनलोड करें

Python के सुपर () कई विरासत के साथ कैसे काम करता है?

मैं पायथन ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग में बहुत अधिक नया हूँ और मुझे super() फ़ंक्शन (नई स्टाइल कक्षाएं) को समझने में परेशानी होती है, खासकर जब यह एकाधिक इन्सेंटेशन की बात आती है

उदाहरण के लिए यदि आपके पास कुछ ऐसा है:

 class First(object): def __init__(self): print "first" class Second(object): def __init__(self): print "second" class Third(First, Second): def __init__(self): super(Third, self).__init__() print "that's it" 

मुझे जो नहीं मिलता है: क्या Third() कक्षा दोनों निर्माता विधियों का उत्तराधिकारी होगा? यदि हां, तो कौन सा सुपर के साथ चलाया जाएगा और क्यों?

और क्या होगा अगर आप दूसरे को चलाना चाहते हैं? मुझे पता है कि इसके पास पायथन विधि रिज़ॉल्यूशन ऑर्डर ( एमआरओ ) के साथ कुछ है।

वेब के समाधान से एकत्रित समाधान "Python के सुपर () कई विरासत के साथ कैसे काम करता है?"

यह अपने ब्लॉग पोस्ट में विधिवत संकल्प आदेश (दो पहले के प्रयासों सहित) में गिदो द्वारा विस्तृत विवरण के साथ विस्तृत है।

आपके उदाहरण में, Third() First.__init__ कॉल करेगा First.__init__ पायथन, कक्षा के अभिभावकों में प्रत्येक विशेषता के लिए देखता है क्योंकि वे बाईं ओर दाईं ओर सूचीबद्ध हैं इस मामले में हम __init__ लिए देख रहे हैं। इसलिए, यदि आप परिभाषित करते हैं

 class Third(First, Second): ... 

पायथन First को देखकर शुरू होगा, और, अगर First में विशेषता नहीं है, तो यह Second पर दिखाई देगा।

यह स्थिति अधिक जटिल हो जाती है, जब विरासत मार्ग को पार करना शुरू हो जाता है (उदाहरण के लिए यदि First Second से विरासत में मिला) अधिक जानकारी के लिए ऊपर दिए गए लिंक को पढ़ें, लेकिन, संक्षेप में, पायथन उस आदेश को बनाए रखने का प्रयास करेगा जिसमें प्रत्येक वर्ग को विरासत सूची में दिखाई देगा, जो कि बच्चे की कक्षा से ही शुरू होगा।

उदाहरण के लिए, यदि आपके पास था:

 class First(object): def __init__(self): print "first" class Second(First): def __init__(self): print "second" class Third(First): def __init__(self): print "third" class Fourth(Second, Third): def __init__(self): super(Fourth, self).__init__() print "that's it" 

एमआरओ होगा [Fourth, Second, Third, First].

वैसे: यदि अजगर एक ठोस विधि रिज़ॉल्यूशन ऑर्डर नहीं मिल सकता है, तो यह उस अपवाद को बढ़ाएगा जो उपयोगकर्ता को आश्चर्यचकित कर सकता है।

एक अस्पष्ट एमआरओ का उदाहरण जोड़ने के लिए संपादित किया गया:

 class First(object): def __init__(self): print "first" class Second(First): def __init__(self): print "second" class Third(First, Second): def __init__(self): print "third" 

क्या Third एमआरओ होना चाहिए [First, Second] या [Second, First] ? कोई स्पष्ट उम्मीद नहीं है, और पायथन एक त्रुटि बढ़ाएगा:

 TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution order (MRO) for bases Second, First 

संपादित करें: मैं कई लोगों को यह तर्क देता हूं कि अभाव में ऊपर वाले कॉल super() कॉल super() ऊपर के उदाहरण हैं, तो मुझे समझाएं: उदाहरणों का मुद्दा यह दिखा रहा है कि कैसे एमआरओ का निर्माण होता है। वे "पहले \ nsecond \ third" या जो कुछ भी प्रिंट करने का इरादा नहीं है । आप कर सकते हैं – और, उदाहरण के साथ घूमते हैं, super() कॉल जोड़ते हैं, देखें कि क्या होता है, और पायथन का उत्तराधिकार मॉडल की गहरी समझ प्राप्त कर सकते हैं। लेकिन मेरा लक्ष्य यह सरल रखना है और यह दर्शाता है कि एमआरओ कैसे बनाया गया है। और जैसा कि मैंने समझाया:

 >>> Fourth.__mro__ (<class '__main__.Fourth'>, <class '__main__.Second'>, <class '__main__.Third'>, <class '__main__.First'>, <type 'object'>) 

आपका कोड, और अन्य उत्तर, सभी छोटी गाड़ी हैं। वे पहले दो वर्गों में सुपर () कॉल्स खो रहे हैं जो काम करने के लिए सहकारी subclassing के लिए आवश्यक हैं।

यहां कोड का एक निश्चित संस्करण है:

 class First(object): def __init__(self): super(First, self).__init__() print("first") class Second(object): def __init__(self): super(Second, self).__init__() print("second") class Third(First, Second): def __init__(self): super(Third, self).__init__() print("that's it") 

सुपर () कॉल को प्रत्येक चरण में एमआरओ में / अगले पद्धति / पाता है, यही वजह है कि पहले और दूसरे को भी यह करना पड़ता है, अन्यथा Second.__init__ के अंत में निष्पादन बंद हो जाता है Second.__init__

मुझे यही मिलता है:

 >>> Third() second first that's it 

मैं बेजान थोड़ा जवाब द्वारा विस्तृत करना चाहता था क्योंकि जब मैंने पाइथन में एक बहु-विरासत पदानुक्रम में सुपर () का उपयोग करने के बारे में पढ़ना शुरू किया, तो मैंने इसे तुरंत प्राप्त नहीं किया।

आपको समझने की आवश्यकता क्या है कि super(MyClass, self).__init__() पूर्ण विरासत पदानुक्रम के संदर्भ में प्रयुक्त विधि संकल्प आदेश (एमआरओ) एल्गोरिथ्म के अनुसार अगले __init__ विधि प्रदान करता है

यह आखिरी हिस्सा समझने में महत्वपूर्ण है आइए उदाहरण को फिर से देखें:

 class First(object): def __init__(self): super(First, self).__init__() print "first" class Second(object): def __init__(self): super(Second, self).__init__() print "second" class Third(First, Second): def __init__(self): super(Third, self).__init__() print "that's it" 

Guido van Rossum द्वारा विधि संकल्प आदेश के बारे में इस अनुच्छेद के अनुसार , __init__ को हल करने का आदेश ("Python 2.3 से पहले") "गहराई से पहले बाएं से सही ट्रवर्सल" का उपयोग करके गणना की जाती है:

 Third --> First --> object --> Second --> object 

सभी डुप्लिकेट को हटाने के बाद, पिछले एक को छोड़कर, हम प्राप्त करते हैं:

 Third --> First --> Second --> object 

तो, जब हम Third कक्षा की एक उदाहरण का इन्स्तांत करते हैं तब क्या होता है, जैसे, x = Third()

  1. तीसरे के एमआरओ __init__ के अनुसार पहले कहा जाता है।

  2. अगला, एमआरओ के अनुसार, __init__ विधि super(Third, self).__init__() पहले के __init__ विधि को हल करता है, जिसे कहा जाता है।

  3. प्रथम super(First, self).__init__() के पहले __init__ super(First, self).__init__() दूसरे के __init__ कॉल करता है , क्योंकि एमआरओ की यही वजह है!

  4. दूसरे super(Second, self).__init__() अंदर __init__ super(Second, self).__init__() ऑब्जेक्ट के __init__ कॉल करता है, जो कुछ भी नहीं है। उसके बाद "दूसरा" प्रिंट होता है

  5. super(First, self).__init__() पूरा होने के बाद, "पहले" छपा हुआ है

  6. super(Third, self).__init__() पूरा होने के बाद, "यह है" मुद्रित किया गया है

यह बताता है कि तीसरे (instantiating) क्यों इनके परिणाम निम्न हैं:

 >>> x = Third() second first that's it 

जटिल मामलों में अच्छी तरह से काम करने के लिए एमआरओ एल्गोरिथ्म को पायथन 2.3 से आगे बढ़ाया गया है, लेकिन मुझे लगता है कि "गहराई से पहले बाएं से सही ट्रवर्सल" का उपयोग करते हुए + "अधिकांश मामलों में डुप्लिकेट्स को अंतिम रूप से हटाने की उम्मीद है" (कृपया टिप्पणी अगर यह मामला नहीं है)। Guido द्वारा ब्लॉग पोस्ट को पढ़ना सुनिश्चित करें!

यह डायमंड समस्या के रूप में जाना जाता है, पृष्ठ में पायथन पर एक प्रविष्टि है, लेकिन संक्षेप में, अजगर सुपरक्लास के तरीकों को बाएं से दाएं पर कॉल करेगा

यह है कि कैसे मैंने कई आवृत्तियों के साथ कई विरासत को शुरू करने के लिए जारी किया और एक ही फ़ंक्शन कॉल के साथ कई मिक्सइन्स बनाए। मुझे स्पष्ट रूप से पारित ** kwargs के लिए चर जोड़ना था और सुपर कॉल के लिए एक समापन बिंदु होने के लिए एक मिक्सइन इंटरफेस जोड़ें।

यहां A बढ़िया आधार वर्ग है और B और C मिक्स इन क्लास हैं जो फ़ंक्शन f प्रदान करते हैं। A और B दोनों के पैरामीटर v अपेक्षा उनके __init__ और C उम्मीद w । फ़ंक्शन f में एक पैरामीटर y लेता है Q तीनों कक्षाओं से प्राप्त होता है। MixInF B और C लिए मिश्रण इंटरफ़ेस C

  • इस संहिता की IPython नोटबुक
  • कोड उदाहरण के साथ गिथूब रेपो
 class A(object): def __init__(self, v, *args, **kwargs): print "A:init:v[{0}]".format(v) kwargs['v']=v super(A, self).__init__(*args, **kwargs) self.v = v class MixInF(object): def __init__(self, *args, **kwargs): print "IObject:init" def f(self, y): print "IObject:y[{0}]".format(y) class B(MixInF): def __init__(self, v, *args, **kwargs): print "B:init:v[{0}]".format(v) kwargs['v']=v super(B, self).__init__(*args, **kwargs) self.v = v def f(self, y): print "B:f:v[{0}]:y[{1}]".format(self.v, y) super(B, self).f(y) class C(MixInF): def __init__(self, w, *args, **kwargs): print "C:init:w[{0}]".format(w) kwargs['w']=w super(C, self).__init__(*args, **kwargs) self.w = w def f(self, y): print "C:f:w[{0}]:y[{1}]".format(self.w, y) super(C, self).f(y) class Q(C,B,A): def __init__(self, v, w): super(Q, self).__init__(v=v, w=w) def f(self, y): print "Q:f:y[{0}]".format(y) super(Q, self).f(y) 

@ वाल्फ़्जो की टिप्पणी के बारे में, आप आमतौर पर, के रूप में उपयोग कर सकते हैं **kwargs :

ऑनलाइन चलने वाला उदाहरण

 class A(object): def __init__(self, a, *args, **kwargs): print("A", a) class B(A): def __init__(self, b, *args, **kwargs): super(B, self).__init__(*args, **kwargs) print("B", b) class A1(A): def __init__(self, a1, *args, **kwargs): super(A1, self).__init__(*args, **kwargs) print("A1", a1) class B1(A1, B): def __init__(self, b1, *args, **kwargs): super(B1, self).__init__(*args, **kwargs) print("B1", b1) B1(a1=6, b1=5, b="hello", a=None) 

परिणाम:

 A None B hello A1 6 B1 5 

आप उन्हें भी स्थिति का उपयोग कर सकते हैं:

 B1(5, 6, b="hello", a=None) 

लेकिन आपको एमआरओ याद रखना होगा, यह वाकई भ्रामक है

मैं थोड़ा परेशान हो सकता हूं, लेकिन मैंने देखा कि लोग हर बार भूल जाते हैं *args और **kwargs का उपयोग करते हैं जब वे किसी विधि को ओवरराइड करते हैं, जबकि इन 'जादू चर' के कुछ बहुत ही उपयोगी और समझदार उपयोग में से एक है

मैं समझता हूं कि यह super() प्रश्न का सीधे उत्तर नहीं देता, लेकिन मुझे लगता है कि यह साझा करने के लिए पर्याप्त प्रासंगिक है।

प्रत्येक विरासत कक्षा को सीधे कॉल करने का एक तरीका भी है:

class First(object): def __init__(self): print '1' class Second(object): def __init__(self): print '2' class Third(First, Second): def __init__(self): Second.__init__(self)
class First(object): def __init__(self): print '1' class Second(object): def __init__(self): print '2' class Third(First, Second): def __init__(self): Second.__init__(self) 

बस ध्यान दें कि यदि आप ऐसा करते हैं, तो आपको प्रत्येक को मैन्युअल रूप से कॉल करना होगा क्योंकि मुझे पूरा यकीन है कि पहले __init__() को नहीं कहा जाएगा।

कक्षाओं के आरंभीकरण के लिए पैरामीटर गुजरने वाला एक अन्य बिंदु अब तक नहीं है। चूंकि super का गंतव्य उप-कक्षा पर निर्भर करता है, पैरामीटर पारित करने का एकमात्र अच्छा तरीका उन सभी को एक साथ पैक कर रहा है। फिर अलग-अलग अर्थों के साथ समान पैरामीटर नाम न रखने के लिए सावधान रहें

उदाहरण:

 class A(object): def __init__(self, **kwargs): print('A.__init__') super().__init__() class B(A): def __init__(self, **kwargs): print('B.__init__ {}'.format(kwargs['x'])) super().__init__(**kwargs) class C(A): def __init__(self, **kwargs): print('C.__init__ with {}, {}'.format(kwargs['a'], kwargs['b'])) super().__init__(**kwargs) class D(B, C): # MRO=D, B, C, A def __init__(self): print('D.__init__') super().__init__(a=1, b=2, x=3) print(D.mro()) D() 

देता है:

 [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>] D.__init__ B.__init__ 3 C.__init__ with 1, 2 A.__init__ 

सुपर क्लास __init__ सीधे मापदंडों के अधिक प्रत्यक्ष कार्य के लिए कॉलिंग आकर्षक है, लेकिन विफल हो जाता है अगर कोई सुपर क्लास में कोई super कॉल हो और / या एमआरओ बदल जाता है और कार्यान्वयन के आधार पर कक्षा ए को कई बार कहा जा सकता है।

निष्कर्ष निकालना: सहकारी विरासत और आरंभीकरण के लिए सुपर और विशिष्ट पैरामीटर बहुत अच्छी तरह से एक साथ काम नहीं कर रहे हैं।

संपूर्ण

मान लें कि सब कुछ object से उतरता है (यदि आप ऐसा नहीं कर रहे हैं), तो पायथन आपके वर्ग उत्तराधिकार के पेड़ के आधार पर एक विधि रिज़ॉल्यूशन ऑर्डर (एमआरओ) की गणना करता है। एमआरओ 3 गुणों को संतुष्ट करता है:

  • एक कक्षा के बच्चे अपने माता-पिता से पहले आते हैं
  • बाबा माता पिता सही माता-पिता से पहले आते हैं
  • एक वर्ग एमआरओ में एक बार प्रकट होता है

यदि ऐसा कोई आदेश मौजूद नहीं है, तो पायथन त्रुटियाँ इसके अंदरूनी कामकाज क्लास क्लास के सी 3 लाइनरिजेशन है। इसके बारे में यहां पढ़ें: https://www.python.org/download/releases/2.3/mro/

इस प्रकार, नीचे दिए गए दोनों उदाहरणों में, यह है:

  1. बच्चा
  2. बाएं
  3. सही
  4. माता-पिता

जब एक विधि कहा जाता है, एमआरओ में उस विधि की पहली घटना एक है जिसे कहा जाता है। उस श्रेणी को लागू नहीं करने वाला कोई भी वर्ग छोड़ दिया गया है। उस विधि के भीतर किसी भी कॉल को एमआरओ में उस विधि की अगली घटना को कॉल करेगा। नतीजतन, यह मायने रखता है कि आप किस क्रम में विरासत में कक्षाएं डालते हैं, और आप कहां तरीके से super को कॉल करते हैं

प्रत्येक विधि में super पहले के साथ

 class Parent (object): def __init__(self): super(Parent, self).__init__() print "parent" class Left(Parent): def __init__(self): super(Left, self).__init__() print "left" class Right(Parent): def __init__(self): super(Right, self).__init__() print "right" class Child(Left, Right): def __init__(self): super(Child, self).__init__() print "child" 

Child() आउटपुट:

 parent right left child 

प्रत्येक विधि में super अंतिम के साथ

 class Parent (object): def __init__(self): print "parent" super(Parent, self).__init__() class Left(Parent): def __init__(self): print "left" super(Left, self).__init__() class Right(Parent): def __init__(self): print "right" super(Right, self).__init__() class Child(Left, Right): def __init__(self): print "child" super(Child, self).__init__() 

Child() आउटपुट:

 child left right parent 
 class First(object): def __init__(self, a): print "first", a super(First, self).__init__(20) class Second(object): def __init__(self, a): print "second", a super(Second, self).__init__() class Third(First, Second): def __init__(self): super(Third, self).__init__(10) print "that's it" t = Third() 

आउटपुट है

 first 10 second 20 that's it 

तीसरे () को कॉल करें तीसरे में परिभाषित init को रेखांकित करता है और उस रूटीन में सुपर को कॉल करें इनिट को पहले में परिभाषित करता है। एमआरओ = [प्रथम, दूसरा] अब सबसे पहले परिभाषित init में कॉल एमआरओ की खोज जारी रखेंगे और init को दूसरे में परिभाषित किया जाएगा, और सुपर को किसी भी कॉल में डिफ़ॉल्ट ऑब्जेक्ट init को मारा जाएगा। मुझे उम्मीद है कि इस उदाहरण ने अवधारणा को स्पष्ट किया।

अगर आप सुपर से पहले कॉल नहीं करते हैं श्रृंखला बंद हो जाती है और आप निम्न आउटपुट प्राप्त करेंगे।

 first 10 that's it 

मैं शीर्ष पर क्या @वियन्सकैपर कहता हूं कि जोड़ना चाहूंगा:

 Third --> First --> object --> Second --> object 

इस मामले में दुभाषिया ऑब्जेक्ट क्लास को फ़िल्टर नहीं करता है क्योंकि इसकी डुप्लिकेट है, बल्कि इसकी वजह यह है कि दूसरा सिर स्थिति में दिखाई देता है और पदानुक्रम सबसेट में पूंछ की स्थिति में दिखाई नहीं देता। जबकि ऑब्जेक्ट केवल पूंछ की स्थिति में प्रकट होता है और प्राथमिकता निर्धारित करने के लिए सी 3 एल्गोरिथ्म में एक मजबूत स्थिति नहीं माना जाता है।

एक श्रेणी सी, एल (सी) की रैखारिसेशन (एमआरओ) है

  • कक्षा सी
  • प्लस का मर्ज
    • अपने माता-पिता पी 1, पी 2, .. की रैखिकरण। = एल (पी 1, पी 2, …) और
    • अपने माता-पिता पी 1, पी 2, की सूची।

रैखिककृत मर्ज, सामान्य वर्गों का चयन करके किया जाता है, जो सूचियों के प्रमुख के रूप में प्रकट होता है और पूंजी नहीं है क्योंकि आदेश के मामलों (नीचे स्पष्ट हो जाएगा)

तीसरी रैखिकरण की गणना निम्नानुसार हो सकती है:

  L(O) := [O] // the linearization(mro) of O(object), because O has no parents L(First) := [First] + merge(L(O), [O]) = [First] + merge([O], [O]) = [First, O] // Similarly, L(Second) := [Second, O] L(Third) := [Third] + merge(L(First), L(Second), [First, Second]) = [Third] + merge([First, O], [Second, O], [First, Second]) // class First is a good candidate for the first merge step, because it only appears as the head of the first and last lists // class O is not a good candidate for the next merge step, because it also appears in the tails of list 1 and 2, = [Third, First] + merge([O], [Second, O], [Second]) // class Second is a good candidate for the second merge step, because it appears as the head of the list 2 and 3 = [Third, First, Second] + merge([O], [O]) = [Third, First, Second, O] 

इस प्रकार निम्न कोड में एक सुपर () कार्यान्वयन के लिए:

 class First(object): def __init__(self): super(First, self).__init__() print "first" class Second(object): def __init__(self): super(Second, self).__init__() print "second" class Third(First, Second): def __init__(self): super(Third, self).__init__() print "that's it" 

यह स्पष्ट हो जाता है कि इस पद्धति का समाधान कैसे किया जाएगा

 Third.__init__() ---> First.__init__() ---> Second.__init__() ---> Object.__init__() ---> returns ---> Second.__init__() - prints "second" - returns ---> First.__init__() - prints "first" - returns ---> Third.__init__() - prints "that's it"