सवाल __Init __ () विधियों के साथ पाइथन सुपर () को समझना [डुप्लिकेट]


इस प्रश्न का उत्तर यहां दिया गया है:

मैं इसका उपयोग समझने की कोशिश कर रहा हूं super()। इसकी प्रकृति से, दोनों बच्चे वर्गों को बनाया जा सकता है, बस ठीक है।

मैं निम्नलिखित 2 बाल वर्गों के बीच वास्तविक अंतर के बारे में जानना चाहता हूं।

class Base(object):
    def __init__(self):
        print "Base created"

class ChildA(Base):
    def __init__(self):
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        super(ChildB, self).__init__()

ChildA() 
ChildB()

1982
2018-02-23 00:30


मूल




जवाब:


super() आपको बेस क्लास को स्पष्ट रूप से संदर्भित करने से बचने देता है, जो अच्छा हो सकता है। लेकिन मुख्य लाभ कई विरासत के साथ आता है, जहां सभी प्रकार के मजेदार चीजें हो सकता है। देखें सुपर पर मानक दस्तावेज़ अगर आप पहले से नहीं हैं।

ध्यान दें कि पायथन 3.0 में वाक्यविन्यास बदल गया: आप बस कह सकते हैं super().__init__() के बजाय super(ChildB, self).__init__() जो आईएमओ काफी अच्छा है।


1427
2018-02-23 00:37



क्या आप इसका एक उदाहरण प्रदान कर सकते हैं super() तर्क के साथ प्रयोग किया जा रहा है? - Steven Vascellaro
क्या आप समझा सकते हैं super(ChildB, self).__init__() यह, क्या करता है ChildB तथा self सुपर के साथ करना है - rimiro


मैं समझने की कोशिश कर रहा हूँ super()

कारण हम उपयोग करते हैं super ऐसा इसलिए है कि सहकारी एकाधिक विरासत का उपयोग करने वाले बाल वर्ग विधि समाधान आदेश (एमआरओ) में सही अगले माता-पिता वर्ग समारोह को कॉल करेंगे।

पायथन 3 में, हम इसे इस तरह से कॉल कर सकते हैं:

class ChildB(Base):
    def __init__(self):
        super().__init__() 

पायथन 2 में, हमें इसका उपयोग करने की आवश्यकता है:

        super(ChildB, self).__init__()

सुपर के बिना, आप एकाधिक विरासत का उपयोग करने की अपनी क्षमता में सीमित हैं:

        Base.__init__(self) # Avoid this.

मैं आगे नीचे बताता हूं।

"वास्तव में इस कोड में क्या अंतर है ?:"

class ChildA(Base):
    def __init__(self):
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        super(ChildB, self).__init__()
        # super().__init__() # you can call super like this in Python 3!

इस कोड में प्राथमिक अंतर यह है कि आपको संकेत में एक परत मिलती है __init__ साथ में super, जो अगली कक्षा निर्धारित करने के लिए वर्तमान वर्ग का उपयोग करता है __init__ एमआरओ में देखने के लिए।

मैं इस अंतर को एक जवाब में बताता हूं कैननिकल सवाल, पायथन में 'सुपर' का उपयोग कैसे करें?, जो दर्शाता है निर्भरता अन्तःक्षेपण तथा सहकारी एकाधिक विरासत

अगर पाइथन नहीं था super

यहां कोड है जो वास्तव में निकटता के बराबर है super (यह सी में कैसे लागू किया गया है, कुछ जांच और फ़ॉलबैक व्यवहार से कम है, और पायथन में अनुवाद किया गया है):

class ChildB(Base):
    def __init__(self):
        mro = type(self).mro()             # Get the Method Resolution Order.
        check_next = mro.index(ChildB) + 1 # Start looking after *this* class.
        while check_next < len(mro):
            next_class = mro[check_next]
            if '__init__' in next_class.__dict__:
                next_class.__init__(self)
                break
            check_next += 1

देशी पायथन की तरह थोड़ा और लिखा:

class ChildB(Base):
    def __init__(self):
        mro = type(self).mro()
        for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
            if hasattr(next_class, '__init__'):
                next_class.__init__(self)
                break

अगर हमारे पास नहीं था super ऑब्जेक्ट, हमें यह मैन्युअल कोड लिखना होगा (या इसे फिर से बनाएं!) यह सुनिश्चित करने के लिए कि हम विधि समाधान आदेश में उचित अगली विधि को कॉल करें!

पाइथन 3 में सुपर यह कैसे करता है बिना स्पष्ट रूप से बताया जा रहा है कि किस वर्ग और उदाहरण से इसे कहा गया था?

यह कॉलिंग स्टैक फ्रेम प्राप्त करता है, और कक्षा को पाता है (पूरी तरह से एक स्थानीय मुक्त चर के रूप में संग्रहीत, __class__, कॉलिंग को क्लास पर बंद करने का काम करता है) और उस फ़ंक्शन के लिए पहला तर्क, जो उदाहरण या कक्षा होना चाहिए जो यह बताता है कि किस विधि समाधान आदेश (एमआरओ) का उपयोग करना है।

चूंकि इसे एमआरओ के लिए पहली तर्क की आवश्यकता है, का उपयोग करते हुए super स्थिर तरीकों के साथ असंभव है

अन्य उत्तरों की आलोचनाएं:

सुपर () आपको बेस क्लास को स्पष्ट रूप से संदर्भित करने से बचने देता है, जो अच्छा हो सकता है। । लेकिन मुख्य लाभ कई विरासत के साथ आता है, जहां मजेदार सामान के सभी प्रकार हो सकते हैं। यदि आप पहले से नहीं हैं तो सुपर पर मानक दस्तावेज़ देखें।

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

मैं यहां समझाऊंगा।

class Base(object):
    def __init__(self):
        print("Base init'ed")

class ChildA(Base):
    def __init__(self):
        print("ChildA init'ed")
        Base.__init__(self)

class ChildB(Base):
    def __init__(self):
        print("ChildB init'ed")
        super(ChildB, self).__init__()

और आइए निर्भरता बनाएं कि हम बच्चे के बाद बुलाए जाएं:

class UserDependency(Base):
    def __init__(self):
        print("UserDependency init'ed")
        super(UserDependency, self).__init__()

अब याद रखें, ChildB सुपर का उपयोग करता है, ChildA नहीं करता:

class UserA(ChildA, UserDependency):
    def __init__(self):
        print("UserA init'ed")
        super(UserA, self).__init__()

class UserB(ChildB, UserDependency):
    def __init__(self):
        print("UserB init'ed")
        super(UserB, self).__init__()

तथा UserA उपयोगकर्ता निर्भरता विधि को कॉल नहीं करता है:

>>> UserA()
UserA init'ed
ChildA init'ed
Base init'ed
<__main__.UserA object at 0x0000000003403BA8>

परंतु UserB, इसलिये ChildB का उपयोग करता है super, कर देता है!:

>>> UserB()
UserB init'ed
ChildB init'ed
UserDependency init'ed
Base init'ed
<__main__.UserB object at 0x0000000003403438>

एक और जवाब के लिए आलोचना

किसी भी परिस्थिति में आपको निम्न कार्य नहीं करना चाहिए, जो एक और उत्तर सुझाता है, क्योंकि जब आप चाइल्डबी को उप-वर्गीकृत करते हैं तो आपको निश्चित रूप से त्रुटियां मिलेंगी:

        super(self.__class__, self).__init__() # Don't do this. Ever.

(वह जवाब चालाक या विशेष रूप से दिलचस्प नहीं है, लेकिन टिप्पणियों में और 17 से अधिक डाउनवॉट्स में प्रत्यक्ष आलोचना के बावजूद, उत्तर देने वाले ने इसे तब तक सुझाव देने में जारी रखा जब तक एक तरह के संपादक ने अपनी समस्या तय नहीं की।)

स्पष्टीकरण: उस उत्तर ने सुपर को कॉल करने का सुझाव दिया:

super(self.__class__, self).__init__()

ये है पूरी तरह गलत। super आइए बच्चों के वर्गों के लिए एमआरओ में अगले माता-पिता को देखें (इस उत्तर का पहला भाग देखें)। यदि आप बताते हैं super हम बच्चे के उदाहरण की विधि में हैं, फिर यह अगली विधि को लाइन में देखेगा (शायद यह एक) जिसके परिणामस्वरूप रिकर्सन हो सकता है, संभवतः एक तार्किक विफलता (उत्तर देने वाले के उदाहरण में, यह करता है) या RuntimeError जब रिकर्सन गहराई पार हो जाती है।

>>> class Polygon(object):
...     def __init__(self, id):
...         self.id = id
...
>>> class Rectangle(Polygon):
...     def __init__(self, id, width, height):
...         super(self.__class__, self).__init__(id)
...         self.shape = (width, height)
...
>>> class Square(Rectangle):
...     pass
...
>>> Square('a', 10, 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'

413
2017-11-25 19:00



मुझे अभी भी इसके चारों ओर अपने सिर को काम करने की ज़रूरत होगी super() कार्य, हालांकि, यह उत्तर गहराई और विवरण के संदर्भ में स्पष्ट रूप से सर्वोत्तम है। मैं जवाब के अंदर आलोचनाओं की भी सराहना करता हूं। यह अन्य उत्तरों में नुकसान की पहचान करके अवधारणा को बेहतर ढंग से समझने में भी मदद करता है। धन्यवाद ! - Yohan Obadia
@ एरॉन हॉल, इतनी विस्तृत जानकारी के लिए धन्यवाद। मुझे लगता है कि अगर वे सही पर्याप्त जानकारी प्रदान नहीं करते हैं तो कुछ जवाब को अनुचित या अपूर्ण के रूप में कॉल करने के लिए सलाहकारों को एक और विकल्प उपलब्ध होना चाहिए (कम से कम)। - hunch
धन्यवाद, यह बहुत उपयोगी था। गरीब / अनुचित उपयोग की आलोचना क्यों और कैसे सुपर का उपयोग करने के लिए बहुत ही चित्रकारी थी - Xarses
पायथन विरासत का बहुत अच्छा स्पष्टीकरण। धन्यवाद - ioaniatr


यह नोट किया गया है कि पायथन 3.0+ में आप इसका उपयोग कर सकते हैं

super().__init__() 

अपनी कॉल करने के लिए, जो संक्षेप में है और आपको माता-पिता या कक्षा के नामों को स्पष्ट रूप से संदर्भित करने की आवश्यकता नहीं है, जो आसान हो सकती है। मैं बस इसे Python 2.7 या उससे कम के लिए जोड़ना चाहता हूं, यह नाम लिखकर इस नाम-असंवेदनशील व्यवहार को प्राप्त करना संभव है self.__class__ कक्षा के नाम के बजाय, यानी

super(self.__class__, self).__init__()

हालांकि, यह ब्रेक कॉल करता है super आपकी कक्षा से प्राप्त होने वाले किसी भी वर्ग के लिए, जहां self.__class__ एक बाल वर्ग वापस कर सकता है। उदाहरण के लिए:

class Polygon(object):
    def __init__(self, id):
        self.id = id

class Rectangle(Polygon):
    def __init__(self, id, width, height):
        super(self.__class__, self).__init__(id)
        self.shape = (width, height)

class Square(Rectangle):
    pass

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

जब मैं एक बनाते हैं Square का उपयोग करते हुए mSquare = Square('a', 10,10), पायथन के लिए निर्माता कहते हैं Rectangle क्योंकि मैंने नहीं दिया है Square इसका अपना कन्स्ट्रक्टर हालांकि, के लिए निर्माता में Rectangle, कॉल super(self.__class__,self) के सुपरक्लास वापस करने जा रहा है mSquare, इसलिए यह कन्स्ट्रक्टर को कॉल करता है Rectangle फिर। इस प्रकार अनंत लूप होता है, जैसा कि @S_C द्वारा उल्लेख किया गया था। इस मामले में, जब मैं दौड़ता हूं super(...).__init__() मैं निर्माता के लिए बुला रहा हूँ Rectangle लेकिन चूंकि मैं इसे कोई तर्क नहीं देता, मुझे एक त्रुटि मिल जाएगी।


223
2017-10-08 20:08



यह जवाब क्या सुझाव देता है, super(self.__class__, self).__init__() यदि आप एक नया प्रदान किए बिना फिर से उपclass करते हैं तो काम नहीं करता है __init__। फिर आपके पास अनंत पुनरावृत्ति है। - glglgl
यह जवाब हास्यास्पद है। यदि आप इस तरह से सुपर दुरुपयोग करने जा रहे हैं, तो आप बेस क्लास नाम को हार्डकोड भी कर सकते हैं। इससे कम गलत है। सुपर के पहले तर्क का पूरा बिंदु यह है कि यह है नहीं जरूरी है कि स्वयं का प्रकार। कृपया rhettinger द्वारा "सुपर माना सुपर" पढ़ें (या उसके कुछ वीडियो देखें)। - Veky
पाइथन 2 के लिए यहां दिखाए गए शॉर्टकट में पहले से ही उल्लेख किए गए नुकसान हैं। इसका उपयोग न करें, या आपका कोड उन तरीकों से तोड़ देगा जो आप भविष्यवाणी नहीं कर सकते हैं। यह "आसान शॉर्टकट" सुपर तोड़ता है, लेकिन आप इसे तब तक महसूस नहीं कर सकते जब तक कि आप डीबगिंग में बहुत समय तक डूब गए हों। यदि सुपर वर्बोज़ है तो पाइथन 3 का प्रयोग करें। - Ryan Hiebert
जवाब संपादित किया। क्षमा करें अगर वह संपादन 180 डिग्री का अर्थ बदलता है, लेकिन अब इस उत्तर को कुछ समझना चाहिए। - Tino
किसी को यह बताने का कोई मतलब नहीं है कि वे कुछ ऐसा कर सकते हैं जो गलत रूप से गलत रूप से प्रदर्शित होता है। आप उपनाम कर सकते हैं echo सेवा मेरे python। कोई भी कभी इसका सुझाव नहीं देगा! - Aaron Hall♦


सुपर का कोई दुष्प्रभाव नहीं है

Base = ChildB

Base()

अपेक्षित के रूप में काम करता है

Base = ChildA

Base()

अनंत रिकर्सन में हो जाता है।


75
2017-11-27 23:26



super कॉल के पास कोई दुष्प्रभाव नहीं है, यह सिर्फ प्रॉक्सी ऑब्जेक्ट बनाता है। मुझे सच में यकीन नहीं है कि यह जवाब क्या कहने की कोशिश कर रहा है super हालांकि एक प्रत्यक्ष माता पिता वर्ग बनाम। - davidism
बयान, "सुपर का कोई दुष्प्रभाव नहीं है," इस संदर्भ में समझ में नहीं आता है। सुपर बस गारंटी देता है कि हम विधि समाधान क्रम में सही अगली कक्षा की विधि को कॉल करते हैं, जबकि दूसरी तरफ अगली विधि को हार्ड-कोड कहा जाता है, जो सहकारी एकाधिक विरासत को और अधिक कठिन बनाता है। - Aaron Hall♦


सिर्फ एक सिर ऊपर ... पायथन 2.7 के साथ, और मैं तब से विश्वास करता हूं super() संस्करण 2.2 में पेश किया गया था, आप केवल कॉल कर सकते हैं super()अगर माता-पिता में से एक वर्ग को अंततः विरासत में प्राप्त होता है object (नई शैली के वर्ग)।

व्यक्तिगत रूप से, पाइथन 2.7 कोड के लिए, मैं उपयोग जारी रखने जा रहा हूं BaseClassName.__init__(self, args) जब तक मुझे वास्तव में उपयोग करने का लाभ नहीं मिलता है super()


68
2018-05-25 17:52



बहुत अच्छा मुद्दा। यदि आप स्पष्ट रूप से उल्लेख नहीं करते हैं: कक्षा बेस (ऑब्जेक्ट): तो आपको उस तरह की त्रुटि मिल जाएगी: "TypeError: टाइप होना चाहिए, क्लासबोज नहीं" - andilabs
@andi मुझे दूसरे दिन उस त्रुटि मिली और अंततः मैंने इसे समझने की कोशिश छोड़ दी। मैं सिर्फ iPython पर गड़बड़ कर रहा था। एक बुरा त्रुटि संदेश का एक मजाकिया दुःस्वप्न अगर वास्तव में कोड था तो मुझे डीबग करना पड़ा! - Two-Bit Alchemist


वास्तव में नहीं है। super() एमआरओ में अगली कक्षा को देखता है (विधि संकल्प आदेश, के साथ उपयोग किया जाता है cls.__mro__) विधियों को कॉल करने के लिए। बस आधार बुलाओ __init__ आधार कहते हैं __init__। जैसा कि होता है, एमआरओ में बिल्कुल एक वस्तु है - आधार। तो आप वास्तव में एक ही चीज़ कर रहे हैं, लेकिन एक अच्छे तरीके से super() (विशेष रूप से यदि आप बाद में एकाधिक विरासत में मिलता है)।


46
2018-02-23 00:34



समझा। क्या आप थोड़ा सा विस्तार कर सकते हैं कि इसके निसर को एकाधिक विरासत के साथ सुपर () का उपयोग क्यों किया जाए? मेरे लिए, आधार .__ init __ (स्वयं) छोटा (क्लीनर) है। अगर मेरे पास दो बेसक्लास थे, तो यह उन दो पंक्तियों, या दो सुपर () लाइनें होगी। या क्या मैंने गलत समझ लिया कि आप "निसर" से क्या मतलब रखते हैं? - Mizipzor
असल में, यह एक सुपर () लाइन होगी। जब आपके पास एकाधिक विरासत है, तो एमआरओ अभी भी फ्लैट है। तो पहला सुपर () .__ init__ कॉल अगली कक्षा के कॉल करता है इस में, जो तब अगली कॉल करता है, और इसी तरह। आपको वास्तव में कुछ दस्तावेज़ों को देखना चाहिए। - Devin Jeanpierre
बाल वर्ग एमआरओ में ऑब्जेक्ट भी शामिल है - एक वर्ग का एमआरओ दिखाई देता है एमआरओ कक्षा चर। - James Brady
यह भी ध्यान रखें कि क्लासिक क्लासेस (प्री 2.2) सुपर का समर्थन नहीं करते हैं - आपको मूल कक्षाओं को स्पष्ट रूप से संदर्भित करना होगा। - James Brady
"बाल वर्ग एमआरओ में वस्तु भी शामिल है - एक वर्ग का एमआरओ दिखाई देता है एमआरओ क्लास वेरिएबल। "यह एक बड़ा ओह है। ओह। - Devin Jeanpierre


मुख्य अंतर यह है कि ChildA.__init__ बिना शर्त कॉल करेंगे Base.__init__ जहाँ तक ChildB.__init__ कॉल करेंगे __init__ में जो भी वर्ग होता है ChildB में पूर्वज selfपूर्वजों की रेखा (जो आप अपेक्षा करते हैं उससे भिन्न हो सकते हैं)।

यदि आप एक जोड़ते हैं ClassC जो एकाधिक विरासत का उपयोग करता है:

class Mixin(Base):
  def __init__(self):
    print "Mixin stuff"
    super(Mixin, self).__init__()

class ChildC(ChildB, Mixin):  # Mixin is now between ChildB and Base
  pass

ChildC()
help(ChildC) # shows that the the Method Resolution Order is ChildC->ChildB->Mixin->Base

फिर Base अब माता पिता का नहीं है ChildB के लिये ChildC उदाहरणों। अभी व super(ChildB, self) इंगित करेगा Mixin अगर self एक है ChildC उदाहरण।

आपने डाला है Mixin के बीच में ChildB तथा Base। और आप इसका लाभ उठा सकते हैं super()

इसलिए यदि आप अपनी कक्षाएं तैयार कर चुके हैं ताकि उन्हें सहकारी एकाधिक विरासत परिदृश्य में उपयोग किया जा सके, तो आप इसका उपयोग करते हैं super क्योंकि आप वास्तव में नहीं जानते कि रनटाइम पर पूर्वजों के लिए कौन जा रहा है।

सुपर सुपर पोस्ट माना जाता है तथा वीडियो के साथ pycon 2015 यह बहुत अच्छी तरह से समझाओ।


22
2017-09-21 06:41



इस। इसका मतलब super(ChildB, self) द्वारा संदर्भित वस्तु के एमआरओ के आधार पर परिवर्तन self, जिसे रनटाइम तक नहीं जाना जा सकता है। दूसरे शब्दों में, लेखक ChildB क्या जानने का कोई तरीका नहीं है super() सभी मामलों में हल हो जाएगा जब तक कि वे इसकी गारंटी नहीं दे सकते ChildB कभी subclassed नहीं होगा। - nispio