python - पाइथन विस्तार-सुपर() पायथन 3 बनाम पायथन 2 का उपयोग कर




inheritance configparser (3)

मूल रूप से मैं इस सवाल से पूछना चाहता था, लेकिन फिर मैंने पाया कि यह पहले से ही सोचा गया था ...

चारों ओर घूमते हुए मुझे configparser को विस्तारित करने का यह उदाहरण मिला। पाइथन 3 के साथ निम्नलिखित कार्य करता है:

$ python3
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2
>>> from configparser import  SafeConfigParser
>>> class AmritaConfigParser(SafeConfigParser):
...     def __init_(self):
...         super().__init__()
... 
>>> cfg = AmritaConfigParser()

लेकिन पायथन 2 के साथ नहीं:

>>> class AmritaConfigParser(SafeConfigParser):
...       def __init__(self):
...           super(SafeConfigParser).init()
... 
>>> cfg = AmritaConfigParser()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: must be type, not classob

फिर मैंने पाइथन न्यू क्लास बनाम ओल्ड क्लास शैलियों (उदाहरण के लिए here पर थोड़ा सा पढ़ा। और अब मैं सोच रहा हूं, मैं कर सकता हूं:

class MyConfigParser(ConfigParser.ConfigParser):
      def Write(self, fp):
          """override the module's original write funcition"""
          ....
      def MyWrite(self, fp):
          """Define new function and inherit all others"""

लेकिन, क्या मुझे इनिट नहीं बुलाया जाना चाहिए? क्या यह पाइथन 2 समकक्ष है:

 class AmritaConfigParser(ConfigParser.SafeConfigParser):
    #def __init__(self):
    #    super().__init__() # Python3 syntax, or rather, new style class syntax ...
    #
    # is this the equivalent of the above ? 
    def __init__(self):
        ConfigParser.SafeConfigParser.__init__(self)

एक विरासत मामले में (जब आप केवल एक वर्ग को उप-वर्ग करते हैं), तो आपकी नई कक्षा को बेस क्लास के तरीके मिलते हैं। इसमें __init__ शामिल है। तो यदि आप इसे अपनी कक्षा में परिभाषित नहीं करते हैं, तो आप आधार से एक प्राप्त करेंगे।

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

ऐसे मामलों में, यदि आप कर सकते हैं तो आपको वास्तव में super उपयोग करना चाहिए, मैं समझाऊंगा क्यों। लेकिन हमेशा आप नहीं कर सकते हैं। समस्या यह है कि आपके सभी बेस वर्गों का भी इसका उपयोग करना चाहिए (और उनके आधार वर्ग भी - पूरे पेड़)।

यदि ऐसा है, तो यह भी सही तरीके से काम करेगा (पायथन 3 में लेकिन आप इसे पायथन 2 में फिर से काम कर सकते हैं - इसमें super भी है):

class A:
    def __init__(self):
        print('A')
        super().__init__()

class B:
    def __init__(self):
        print('B')
        super().__init__()

class C(A, B):
    pass

C()
#prints:
#A
#B

ध्यान दें कि दोनों बेस क्लास super उपयोग कैसे करते हैं, भले ही उनके पास अपनी खुद की बेस क्लास न हों।

super क्या करता है: यह एमआरओ (विधि संकल्प आदेश) में अगली कक्षा से विधि को कॉल करता है। सीआरओ के लिए एमआरओ है: (C, A, B, object) । आप इसे देखने के लिए C.__mro__ प्रिंट कर सकते हैं।

इसलिए, C A से __init__ A और super में A.__init__ कॉल B.__init__ ( B एमआरओ में A का पालन करता है)।

तो C में कुछ भी नहीं करके, आप दोनों को कॉल करना समाप्त कर देते हैं, जो आप चाहते हैं।

अब यदि आप super का उपयोग नहीं कर रहे थे, तो आप विरासत A.__init__ (पहले की तरह) को समाप्त कर देंगे लेकिन इस बार ऐसा कुछ भी नहीं है जो आपके लिए B.__init__ को कॉल करेगा।

class A:
    def __init__(self):
        print('A')

class B:
    def __init__(self):
        print('B')

class C(A, B):
    pass

C()
#prints:
#A

इसे ठीक करने के लिए आपको C.__init__ को परिभाषित C.__init__ :

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

इसके साथ समस्या यह है कि अधिक जटिल एमआई पेड़ों में, कुछ वर्गों के __init__ विधियों को एक से अधिक बार बुलाया जा सकता है जबकि सुपर / एमआरओ गारंटी देता है कि उन्हें केवल एक बार बुलाया जाता है।


पाइथन 3 के लिए बस एक सरल और पूर्ण उदाहरण है, जो कि ज्यादातर लोग अब उपयोग कर रहे हैं।

class MySuper(object):
    def __init__(self,a):
        self.a = a

class MySub(MySuper):
    def __init__(self,a,b):
        self.b = b
        super().__init__(a)

my_sub = MySub(42,'chickenman')
print(my_sub.a)
print(my_sub.b)

देता है

42
chickenman

  • super() (तर्क के बिना) पायथन 3 ( __class__ के साथ) में पेश किया गया था:

    super() -> same as super(__class__, self)
    

    तो यह पाइथन 2 नए शैली के वर्गों के बराबर होगा:

    super(CurrentClass, self)
    
  • पुराने शैली के वर्गों के लिए आप हमेशा उपयोग कर सकते हैं:

     class Classname(OldStyleParent):
        def __init__(self, *args, **kwargs):
            OldStyleParent.__init__(self, *args, **kwargs)
    




configparser