अजगर में वंशानुक्रम और ओवरराइडिंग __init__


129

मैं 'डाइव इनटू पायथन' पढ़ रहा था और कक्षाओं में अध्याय में यह उदाहरण देता है:

class FileInfo(UserDict):
    "store file metadata"
    def __init__(self, filename=None):
        UserDict.__init__(self)
        self["name"] = filename

लेखक तब कहता है कि यदि आप __init__विधि को ओवरराइड करना चाहते हैं, तो आपको __init__सही पैरामीटर के साथ अभिभावक को स्पष्ट रूप से कॉल करना होगा ।

  1. क्या होगा यदि उस FileInfoवर्ग में एक से अधिक पूर्वजों की कक्षा थी?
    • क्या मुझे पूर्वजों की सभी __init__विधियों को स्पष्ट रूप से बताना है ?
  2. इसके अलावा, क्या मुझे ऐसा किसी अन्य तरीके से करना होगा जिसे मैं ओवरराइड करना चाहता हूं?

3
ध्यान दें कि ओवरलोडिंग ओवरराइडिंग से एक अलग अवधारणा है।
सना

जवाबों:


158

उपवर्ग-सुपरक्लास कॉलिंग के संबंध में पुस्तक थोड़ी दिनांकित है। यह अंतर्निहित कक्षाओं को उपवर्ग के संबंध में थोड़ा सा दिनांकित है।

आजकल ऐसा दिखता है:

class FileInfo(dict):
    """store file metadata"""
    def __init__(self, filename=None):
        super(FileInfo, self).__init__()
        self["name"] = filename

निम्नलिखित पर ध्यान दें:

  1. हम सीधे उपवर्ग कर सकते हैं में निर्मित कक्षाएं, जैसे dict, list, tuple, आदि

  2. superसमारोह हैंडल इस वर्ग के सुपर-क्लास पर नज़र रखने और उचित रूप से उन में कार्यों बुला।


5
क्या मुझे एक बेहतर पुस्तक / ट्यूटोरियल की तलाश करनी चाहिए?
liewl

2
तो कई विरासत के मामले में, क्या सुपर () आपकी ओर से उन सभी को ट्रैक करता है?
दाना

तानाशाही। init __ (स्व), वास्तव में, लेकिन इसके साथ कुछ भी गलत नहीं है - सुपर (...) कॉल केवल एक अधिक सिंटैक्स प्रदान करता है। (मुझे यकीन नहीं है कि यह एकाधिक वंशानुक्रम के लिए कैसे काम करता है, मुझे लगता है कि यह केवल एक सुपरक्लास इनिट पा सकता है )
डेविड जेड

4
सुपर () का आशय यह है कि यह कई उत्तराधिकार संभालता है। नुकसान यह है कि व्यवहार में कई विरासत अभी भी बहुत आसानी से टूट जाती है (देखें < fuhm.net/super-harmful )।
sth

2
हां, कई तर्क और आधार वर्ग के निर्माण संबंधी तर्क देने के मामले में, आप आमतौर पर खुद को कंस्ट्रक्टरों को मैन्युअल रूप से बुलाते हैं।
टॉर्स्टन मारेक

18

प्रत्येक वर्ग में जिसे आपको विरासत में प्राप्त करने की आवश्यकता है, आप प्रत्येक वर्ग के एक लूप को चला सकते हैं, जिसमें बच्चे की कक्षा शुरू करने के लिए init'd की आवश्यकता होती है ... एक उदाहरण जो कॉपी किया जा सकता है उसे बेहतर समझा जा सकता है ...

class Female_Grandparent:
    def __init__(self):
        self.grandma_name = 'Grandma'

class Male_Grandparent:
    def __init__(self):
        self.grandpa_name = 'Grandpa'

class Parent(Female_Grandparent, Male_Grandparent):
    def __init__(self):
        Female_Grandparent.__init__(self)
        Male_Grandparent.__init__(self)

        self.parent_name = 'Parent Class'

class Child(Parent):
    def __init__(self):
        Parent.__init__(self)
#---------------------------------------------------------------------------------------#
        for cls in Parent.__bases__: # This block grabs the classes of the child
             cls.__init__(self)      # class (which is named 'Parent' in this case), 
                                     # and iterates through them, initiating each one.
                                     # The result is that each parent, of each child,
                                     # is automatically handled upon initiation of the 
                                     # dependent class. WOOT WOOT! :D
#---------------------------------------------------------------------------------------#



g = Female_Grandparent()
print g.grandma_name

p = Parent()
print p.grandma_name

child = Child()

print child.grandma_name

2
यह लूप के Child.__init__लिए आवश्यक नहीं है। जब मैं इसे उदाहरण से हटाता हूं तो मैं अभी भी "दादी" को छापता हूं। क्या दादा दादी Parentकक्षा द्वारा नियंत्रित नहीं हैं ?
एडम

4
मुझे लगता है कि पहले से ही माता-पिता की निष्क्रियता से ग्रेटरपेंट इनिट को संभाल रहे हैं, वे नहीं हैं?
johk95

15

आप वास्तव में नहीं है है कॉल करने के लिए __init__आधार वर्ग (ते) के तरीकों, लेकिन आप आमतौर पर चाहते हैं यह करने के लिए क्योंकि आधार वर्ग के लिए कुछ महत्वपूर्ण initializations वहाँ है कि काम करने के लिए कक्षाओं के तरीकों में से बाकी के लिए आवश्यक हैं करेंगे।

अन्य तरीकों के लिए यह आपके इरादों पर निर्भर करता है। अगर आप बस बेस क्लासेस के व्यवहार में कुछ जोड़ना चाहते हैं, तो आप बेस क्लासेज मेथड को अपने कोड में कॉल करना चाहेंगे। यदि आप व्यवहार को मौलिक रूप से बदलना चाहते हैं, तो आप बेस क्लास की पद्धति को नहीं कह सकते हैं और सभी कार्यक्षमता को सीधे व्युत्पन्न वर्ग में लागू कर सकते हैं।


4
तकनीकी पूर्णता के लिए, कुछ कक्षाएं, जैसे थ्रेडिंग। थ्रेड, अगर आप कभी भी माता-पिता के इनिट को कॉल करने से बचने की कोशिश करते हैं, तो विशाल त्रुटियां फेंक देंगे ।
डेविड बर्जर

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

2
"आधार वर्गों को शुरू नहीं करने का सुझाव देना इतने तरीकों से गलत है।" किसी ने भी आधार वर्ग को शुरू नहीं करने का सुझाव दिया है। उत्तर को ध्यान से पढ़ें। यह सब इरादा है। 1) यदि आप बेस क्लास को 'इनिट लॉजिक' के रूप में छोड़ना चाहते हैं, तो आप अपने व्युत्पन्न वर्ग में इनिट विधि को ओवरराइड नहीं करते हैं। 2) अगर आप बेस क्लास से इनिट लॉजिक को आगे बढ़ाना चाहते हैं, तो आप अपनी इनिट मेथड को डिफाइन करते हैं और फिर बेस क्लास को 'इनिट मेथड' कहते हैं। 3) यदि आप बेस क्लास के इनिट लॉजिक को बदलना चाहते हैं, तो आप बेस क्लास से कॉल न करते हुए अपनी खुद की इनिट विधि को परिभाषित करते हैं।
१omb:१६ पर wombatonfire

4

यदि FileInfo वर्ग में एक से अधिक पूर्वजों की श्रेणी है, तो आपको निश्चित रूप से उनके सभी __in __ () फ़ंक्शन को कॉल करना चाहिए। आपको __del __ () फ़ंक्शन के लिए भी ऐसा करना चाहिए, जो एक विध्वंसक है।


2

हां, आपको __init__प्रत्येक मूल वर्ग के लिए कॉल करना होगा । वही फ़ंक्शन के लिए जाता है, यदि आप एक फ़ंक्शन को ओवरराइड कर रहे हैं जो दोनों माता-पिता में मौजूद है।

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