__Init __ () को पैरेंट क्लास के __init __ () कॉल करना चाहिए?


132

मैंने इसका उपयोग ऑब्जेक्टिव-सी में किया है, मुझे यह निर्माण मिला है:

- (void)init {
    if (self = [super init]) {
        // init class
    }
    return self;
}

क्या पायथन को भी माता-पिता के कार्यान्वयन के लिए कॉल करना चाहिए __init__?

class NewClass(SomeOtherClass):
    def __init__(self):
        SomeOtherClass.__init__(self)
        # init class

इस के लिए भी सही / गलत है __new__()और __del__()?

संपादित करें: एक बहुत ही समान प्रश्न है: पायथन में वंशानुक्रम और ओवरराइडिंग__init__


आपने अपना कोड काफी बदल दिया है। मैं समझ सकता हूं कि मूल objectएक टाइपो था। लेकिन अब आपके पास superअपने प्रश्न का शीर्षक भी नहीं है।
साइलेंटगॉस्ट

मुझे लगा कि सुपर को मूल वर्ग के नाम के रूप में उपयोग किया जाता है। मुझे नहीं लगता था कि कोई भी समारोह के बारे में सोचेगा। मुझे किसी भी गलतफहमी के लिए खेद है।
जॉर्ज शॉली

क्यों नहीं स्वत: सुपर कॉल प्रश्न: stackoverflow.com/questions/3782827/…
Ciro Santilli 病 call call call

जवाबों:


67

पायथन में, सुपर-क्लास को कॉल करना ' __init__वैकल्पिक है। यदि आप इसे कहते हैं, तो यह भी वैकल्पिक है कि क्या superपहचानकर्ता का उपयोग करना है, या सुपर क्लास को स्पष्ट रूप से नाम देना है या नहीं:

object.__init__(self)

ऑब्जेक्ट के मामले में, सुपर विधि को कॉल करना कड़ाई से आवश्यक नहीं है, क्योंकि सुपर विधि खाली है। उसी के लिए __del__

दूसरी ओर, इसके लिए __new__, आपको वास्तव में सुपर मेथड को कॉल करना चाहिए, और इसकी वापसी का उपयोग नव-निर्मित वस्तु के रूप में करना चाहिए - जब तक कि आप स्पष्ट रूप से कुछ अलग नहीं करना चाहते।


तो सिर्फ सुपर के कार्यान्वयन को बुलाने के लिए कोई सम्मेलन नहीं है?
जॉर्ज शॉली

5
पुरानी शैली की कक्षाओं में, आप केवल सुपर इनिट कह सकते हैं यदि सुपर क्लास में वास्तव में एक इनट डिफाइन होता है (जो अक्सर ऐसा नहीं होता है)। इसलिए, लोग आमतौर पर इसे सिद्धांत से बाहर करने के बजाय सुपर विधि को कॉल करने के बारे में सोचते हैं।
मार्टिन वी। लोविस

1
यदि अजगर में सिंटैक्स सरल था [super init], तो यह अधिक सामान्य होगा। बस एक सट्टा सोचा; पायथन 2.x में सुपर निर्माण मेरे लिए थोड़ा अजीब है।
u0b34a0f6ae

यहाँ एक दिलचस्प लगता है (और संभवतः विरोधाभासी) उदाहरण: bytes.com/topic/python/answers/… init
mlvljr

"वैकल्पिक" इसमें आपको कॉल करने की आवश्यकता नहीं है, लेकिन यदि आप इसे कॉल नहीं करते हैं, तो यह स्वचालित रूप से कॉल नहीं किया जाएगा।
मैकके

140

यदि आपको __init__वर्तमान कक्षा में जो कुछ किया जा रहा है उसके अतिरिक्त सुपर से कुछ करने की आवश्यकता है, तो आपको __init__,इसे स्वयं कॉल करना होगा, क्योंकि यह स्वचालित रूप से नहीं होगा। लेकिन अगर आपको __init__,इसे कॉल करने के लिए सुपर की कोई ज़रूरत नहीं है। उदाहरण:

>>> class C(object):
        def __init__(self):
            self.b = 1


>>> class D(C):
        def __init__(self):
            super().__init__() # in Python 2 use super(D, self).__init__()
            self.a = 1


>>> class E(C):
        def __init__(self):
            self.a = 1


>>> d = D()
>>> d.a
1
>>> d.b  # This works because of the call to super's init
1
>>> e = E()
>>> e.a
1
>>> e.b  # This is going to fail since nothing in E initializes b...
Traceback (most recent call last):
  File "<pyshell#70>", line 1, in <module>
    e.b  # This is going to fail since nothing in E initializes b...
AttributeError: 'E' object has no attribute 'b'

__del__उसी तरह है, (लेकिन __del__अंतिम रूप देने के लिए भरोसा करने से सावधान रहें - इसके बजाय इसे कथन के साथ करने पर विचार करें)।

मैं शायद ही कभी उपयोग करता __new__. हूं मैं सभी प्रारंभिककरण करता हूं__init__.


3
कक्षा D (C) की परिभाषा को इस तरह ठीक किया जाना चाहिएsuper(D,self).__init__()
eyquem

11
सुपर ()। init __ () केवल पायथन 3 में काम करता है। अजगर 2 में आपको सुपर (डी, स्व) की आवश्यकता है। init __ ()
जैकिंडा

“अगर आपको सुपर इनिट से कुछ चाहिए ..." - यह एक बहुत ही समस्याग्रस्त बयान है क्योंकि यह इस बात का मामला नहीं है कि क्या आपको / उपवर्ग को "कुछ" चाहिए, लेकिन क्या वैध होने के लिए आधार वर्ग को कुछ चाहिए? बेस क्लास उदाहरण और सही ढंग से काम करते हैं। व्युत्पन्न वर्ग के कार्यान्वयन के रूप में, बेस क्लास इंटर्नल्स ऐसी चीजें हैं जिन्हें आपको पता नहीं होना चाहिए / नहीं होना चाहिए, और यहां तक ​​कि अगर आप ऐसा करते हैं क्योंकि आपने दोनों को लिखा है या आंतरिक दस्तावेज हैं, तो आधार का डिज़ाइन भविष्य में बदल सकता है और खराब लिखे जाने के कारण टूट सकता है व्युत्पन्न वर्ग। इसलिए हमेशा यह सुनिश्चित करें कि बेस क्लास को पूरी तरह से शुरू किया जाए।
निक

105

एनोन के उत्तर में:
"यदि आपको __init__वर्तमान कक्षा में किए जा रहे कार्यों के अतिरिक्त सुपर से कुछ करने की आवश्यकता है __init__, तो आपको इसे स्वयं कॉल करना होगा, क्योंकि यह स्वचालित रूप से नहीं होगा"

यह अविश्वसनीय है: वह विरासत के सिद्धांत के बिल्कुल विपरीत है।


ऐसा नहीं है कि "सुपर से कुछ __init__ (...) स्वचालित रूप से नहीं होगा" , यह है कि यह स्वचालित रूप से होता है, लेकिन ऐसा नहीं होता है क्योंकि आधार-वर्ग ' __init__व्युत्पन्न- वर्ग की परिभाषा से अधिक है__init__

तो फिर, एक व्युत्पन्न 'क्यों' को परिभाषित करते हुए __init__, क्योंकि यह उकसाता है कि जब कोई व्यक्ति विरासत में मिले तो क्या करना है?

ऐसा इसलिए है क्योंकि किसी को किसी ऐसी चीज़ को परिभाषित करने की ज़रूरत है जो बेस-क्लास में नहीं की गई है __init__, और इसे प्राप्त करने की एकमात्र संभावना है कि इसका निष्पादन एक व्युत्पन्न वर्ग के __init__फ़ंक्शन में किया जाए।
दूसरे शब्दों में, किसी को बेस-क्लास में कुछ चाहिए__init__ चाहिए होता है , इसके अलावा बेस-क्लासेज़ में स्वचालित रूप से क्या किया जाएगा ' __init__अगर यह बाद वाला नहीं था।
इसके विपरीत नहीं।


फिर, समस्या यह है कि बेस-क्लास में मौजूद वांछित निर्देश ' __init__तात्कालिकता के क्षण में अधिक सक्रिय नहीं हैं। इस निष्क्रियता को दूर करने के लिए, कुछ विशेष की आवश्यकता है: स्पष्ट रूप से बेस-क्लास को कॉल करना '__init__ करना , KEEP के लिए , न कि ADD के लिए, बेस क्लास द्वारा किया गया इनिशियलाइज़ेशन ' __init__। आधिकारिक डॉक में यही कहा गया है:

एक व्युत्पन्न वर्ग में एक ओवरराइडिंग विधि वास्तव में उसी नाम के आधार वर्ग विधि को बदलने के बजाय विस्तार करना चाह सकती है । बेस क्लास पद्धति को सीधे कॉल करने का एक सरल तरीका है: बस BaseClassName.methodname (स्वयं, तर्क) को कॉल करें।
http://docs.python.org/tutorial/classes.html#inheritance

यह सब कहानी है:

  • जब उद्देश्य केईपी को बेस-क्लास द्वारा शुरू की गई शुरुआत है, जो कि शुद्ध विरासत है, तो कुछ विशेष की आवश्यकता नहीं है, एक को केवल परिभाषित करने से बचना चाहिए __init__ व्युत्पन्न वर्ग में फ़ंक्शन

  • जब उद्देश्य आधार वर्ग द्वारा किए गए इनिशियलाइज़ेशन को पुन: लागू करना है, __init__ करना है इसे व्युत्पन्न वर्ग में परिभाषित किया जाना चाहिए

  • जब उद्देश्य ADD प्रक्रियाओं को बेस-क्लास द्वारा किए गए इनिशियलाइज़ेशन के लिए है, तो एक व्युत्पन्न वर्ग __init__ को परिभाषित किया जाना चाहिए, जिसमें बेस क्लास के लिए एक स्पष्ट कॉल शामिल है।__init__


अनोन के पद में मुझे जो अचरज होता है, वह केवल यह नहीं है कि वह वंशानुक्रम के सिद्धांत के विपरीत व्यक्त करता है, बल्कि यह भी है कि 5 लोग बिना बालों को मोड़े हुए उस उत्थान से गुजर रहे हैं, और इसके अलावा 2 वर्षों में प्रतिक्रिया देने वाला कोई नहीं है एक धागा जिसका दिलचस्प विषय अपेक्षाकृत अक्सर पढ़ा जाना चाहिए।


1
मुझे यकीन था कि यह पोस्ट अप करने वाला था। मुझे डर है कि मेरे पास कारणों के बारे में बहुत स्पष्टीकरण नहीं होगा। यह एक पाठ का विश्लेषण करने की तुलना में कम करना आसान है जो समझ से बाहर है। मैं एक लंबे समय से अंत में अनोन की पोस्ट को समझने की कोशिश कर रहा था, इससे पहले कि मुझे एहसास हुआ कि यह स्पष्ट रूप से लिखा गया था और बहुत अधिक आधिकारिक नहीं था। शायद यह किसी के लिए लगभग सही समझा जा सकता है जो विरासत के बारे में जानता है; लेकिन मुझे यह भ्रम लगता है जब किसी व्यक्ति द्वारा विरासत के बारे में अस्थिर धारणाओं को पढ़ा जाता है, एक विषय जो सामान्य रूप से चट्टान के पानी के रूप में स्पष्ट नहीं है
आइकैम

2
"मुझे यकीन है कि इस पोस्ट को अपटेड किया जा रहा था ..." मुख्य मुद्दा यह है कि आप पार्टी के लिए थोड़ा देर हो चुके हैं, और अधिकांश लोग पहले कुछ उत्तरों से आगे नहीं पढ़ सकते हैं। जिस तरह से महान व्याख्या +1
गेरेट

शानदार जवाब है यह।
त्रिशूल

3
आपने हारून से उद्धृत वाक्य में "इसके अतिरिक्त" महत्वपूर्ण शब्दों को याद किया। हारून का कथन पूरी तरह से सही है, और यह कहता है कि आपने क्या कहा।
ग्रीनएजेड जेड

1
यह पहला स्पष्टीकरण है जिसने अजगर की डिजाइन पसंद को स्पष्ट किया है।
जोसेफ गार्विन

20

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

निम्नलिखित उदाहरण पर विचार करें:

>>> class A:
    def __init__(self, val):
        self.a = val


>>> class B(A):
    pass

>>> class C(A):
    def __init__(self, val):
        A.__init__(self, val)
        self.a += val


>>> A(4).a
4
>>> B(5).a
5
>>> C(6).a
12

मैंने अपने उदाहरण से सुपर कॉल को हटा दिया है, क्या मैं जानना चाहता हूं कि क्या माता-पिता को इनिट के कार्यान्वयन को कॉल करना चाहिए या नहीं।
जॉर्ज स्कोली

आप तब शीर्षक संपादित करना चाह सकते हैं। लेकिन मेरा जवाब अभी भी खड़ा है।
साइलेंटगॉस्ट

5

कोई कठिन और तेज़ नियम नहीं है। एक वर्ग के लिए प्रलेखन से संकेत मिलता है कि क्या उपवर्गों को सुपरक्लास पद्धति को कॉल करना चाहिए। कभी-कभी आप सुपरक्लास व्यवहार को पूरी तरह से बदलना चाहते हैं, और अन्य समय में इसे बढ़ाते हैं - यानी सुपरक्लास कॉल से पहले और / या बाद में अपना स्वयं का कोड कॉल करें।

अद्यतन: वही मूल तर्क किसी भी विधि कॉल पर लागू होता है। कंस्ट्रक्टर्स को कभी-कभी विशेष रूप से विचार करने की आवश्यकता होती है (जैसा कि वे अक्सर राज्य निर्धारित करते हैं जो व्यवहार निर्धारित करता है) और विध्वंसक क्योंकि वे समानांतर कंस्ट्रक्टर (जैसे संसाधनों के आवंटन में, जैसे डेटाबेस कनेक्शन)। लेकिन render()एक विजेट की विधि के लिए भी यही कह सकते हैं ।

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


आपने कहा था कि कभी-कभी सुपरक्लास कॉल से पहले कोई अपना कोड कॉल करना चाहेगा। ऐसा करने के लिए, किसी को मूल वर्ग के कार्यान्वयन के ज्ञान की आवश्यकता होती है, जो ओपीपी का उल्लंघन करेगा।
जॉर्ज शॉली

4

IMO, आपको इसे कॉल करना चाहिए। यदि आपका सुपरक्लास है object, तो आपको नहीं करना चाहिए, लेकिन अन्य मामलों में मुझे लगता है कि इसे न कहना असाधारण है। जैसा कि पहले ही दूसरों ने उत्तर दिया है, यह बहुत सुविधाजनक है यदि आपकी कक्षा को __init__स्वयं को ओवरराइड नहीं करना है, उदाहरण के लिए जब इसे शुरू करने के लिए कोई अतिरिक्त (आंतरिक) स्थिति नहीं है।


2

हां, आपको हमेशा __init__एक अच्छे कोडिंग अभ्यास के रूप में बेस क्लास को स्पष्ट रूप से कॉल करना चाहिए । ऐसा करने के लिए भूल जाने से सूक्ष्म समस्याएँ हो सकती हैं या समय त्रुटियाँ हो सकती हैं। यह सच है भले ही__init__ कोई पैरामीटर न ले। यह अन्य भाषाओं के विपरीत है जहां संकलक आपके लिए बेस क्लास कंस्ट्रक्टर कहेगा। अजगर ऐसा नहीं करता है!

बेस क्लास को हमेशा कॉल करने का मुख्य कारण _init__ को यह है कि बेस क्लास आम तौर पर मेंबर वेरिएबल बना सकती है और उन्हें डिफॉल्ट करने के लिए इनिशियलाइज़ कर सकती है। इसलिए यदि आप बेस क्लास इनिट को नहीं कहते हैं, तो उस कोड में से कोई भी निष्पादित नहीं किया जाएगा और आप बेस क्लास के साथ समाप्त हो जाएंगे जिसमें कोई सदस्य चर नहीं है।

उदाहरण :

class Base:
  def __init__(self):
    print('base init')

class Derived1(Base):
  def __init__(self):
    print('derived1 init')

class Derived2(Base):
  def __init__(self):
    super(Derived2, self).__init__()
    print('derived2 init')

print('Creating Derived1...')
d1 = Derived1()
print('Creating Derived2...')
d2 = Derived2()

यह प्रिंट ।।

Creating Derived1...
derived1 init
Creating Derived2...
base init
derived2 init

इस कोड को चलाएं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.