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


103

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

मेरे चारों ओर गुग्लिंग को विस्तारक का यह उदाहरण मिला । पायथन 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

तब मैंने पायथन न्यू क्लास बनाम ओल्ड क्लास स्टाइल (जैसे यहाँ) पर थोड़ा पढ़ा और अब मैं सोच रहा हूँ, मैं कर सकता हूँ:

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"""

लेकिन, मैं init फोन नहीं करना चाहिए? क्या पायथन 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)

1
आपके उदाहरण में आपको __init__()उपवर्ग में परिभाषित करने की आवश्यकता नहीं है यदि यह सब करता है तो सुपर क्लास कहलाता है ' __init__()(या तो पायथन 2 या 3 में) - इसके बजाय बस सुपर को विरासत में मिला दें।
मार्टीन्यू

उपयोगी संदर्भ: amyboyle.ninja/Python-Inheritance
nu everest

को सही लिंक के साथ उपयोगी संदर्भ: amyboyle.ninja/Python-Inheritance
fearless_fool

जवाबों:


155
  • 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)

8
-1। इस जवाब ने मेरे लिए कुछ भी स्पष्ट नहीं किया। अजगर 2 में, super(__class__)देता है NameError: global name '__class__' is not defined, और super(self.__class__)गलत भी है। आप चाहिए एक दूसरा तर्क है, जो सुझाव है कि आप क्या करने की जरूरत के रूप में एक उदाहरण प्रदान करते हैं super(self.__class__, self), लेकिन वह यह है कि गलत । यदि Class2से विरासत में मिली Class1और Class1कॉल super(self.__class__, self).__init__(), Class1की __init__तो होगा ही फोन जब का एक उदाहरण instantiating Class2
jpmc26

एक बिंदु को स्पष्ट करने के लिए, मैं पायथन 2 में TypeError: super() takes at least 1 argument (0 given)कॉल करने की कोशिश कर रहा हूं super(self.__class__)। 2. (जो बहुत मायने नहीं रखता है, लेकिन यह दर्शाता है कि इस उत्तर से कितनी जानकारी गायब है।)
jpmc26

3
@ jpmc26: python2 में आपको यह त्रुटि मिलती है क्योंकि आपके __init__()द्वारा अनबाउंड सुपर ऑब्जेक्ट पर तर्क के बिना कॉल करने की कोशिश की जा रही है (जिसे आप super(self.__class__)केवल एक तर्क के साथ कॉल करके प्राप्त करते हैं ), आपको एक बाध्य सुपर ऑब्जेक्ट की आवश्यकता है तब इसे काम करना चाहिए super(CurrentClass, self).__init__():। उपयोग न करें self.__class__क्योंकि यह हमेशा एक ही वर्ग को संदर्भित करेगा जब माता-पिता को बुलाते हैं और उसके बाद एक अनंत लूप बनाते हैं यदि वह माता-पिता भी ऐसा ही करता है।
माता

__class__(सदस्य) पायथन 2 में भी मौजूद है ।
CristiFati

3
@CristiFati यह __class__सदस्य के बारे में नहीं है, लेकिन निहित रूप से बनाए गए शाब्दिक __class__बंद होने के बारे में है जो हमेशा उस वर्ग को संदर्भित करता है जिसे वर्तमान में परिभाषित किया जा रहा है, जो python2 में मौजूद नहीं है।
माता

48

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

यदि आप एक से अधिक वंशानुक्रम (एक समय में एक से अधिक वर्ग उपवर्ग) का परिचय देते हैं तो चीजें जटिल होने लगती हैं। ऐसा इसलिए है क्योंकि यदि एक से अधिक बेस क्लास हैं __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है: (C, A, B, object)। आप C.__mro__इसे देखने के लिए प्रिंट कर सकते हैं।

तो, Cinherits __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__:

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

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


10
Notice how both base classes use super even though they don't have their own base classes.उनके पास है। Py3k में हर वर्ग उपवर्ग वस्तु है।
उर्फम

यह वह उत्तर है जिसकी मुझे तलाश थी, लेकिन यह नहीं पता था कि कैसे पूछा जाए। एमआरओ विवरण अच्छा है।
dturvene

27

संक्षेप में, वे समकक्ष हैं। आइए एक इतिहास देखें:

(1) सबसे पहले, फ़ंक्शन इस तरह दिखता है।

    class MySubClass(MySuperClass):
        def __init__(self):
            MySuperClass.__init__(self)

(2) कोड को अधिक सार (और अधिक पोर्टेबल) बनाने के लिए। सुपर-क्लास प्राप्त करने के लिए एक सामान्य विधि का आविष्कार किया गया है:

    super(<class>, <instance>)

और इनिट फ़ंक्शन हो सकता है:

    class MySubClassBetter(MySuperClass):
        def __init__(self):
            super(MySubClassBetter, self).__init__()

हालाँकि, कक्षा और उदाहरण दोनों को स्पष्ट रूप से पास करने की आवश्यकता है DRY (डोंट रिपीट योरसेल्फ) नियम को थोड़ा तोड़ दें।

(३) वी ३ में। यह अधिक स्मार्ट है,

    super()

ज्यादातर मामलों में पर्याप्त है। आप http://www.python.org/dev/peps/pep-3135/ का उल्लेख कर सकते हैं


22

बस पायथन 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

3

एक और पायथन 3 कार्यान्वयन जिसमें सुपर () के साथ एब्सट्रैक्ट कक्षाओं का उपयोग शामिल है। आपको वह याद रखना चाहिए

super().__init__(name, 10)

के रूप में एक ही प्रभाव है

Person.__init__(self, name, 10)

याद रखें कि सुपर () में एक छिपी हुई 'स्व' है, इसलिए सुपरक्लास इनिट विधि पर एक ही ऑब्जेक्ट गुजरता है और उस ऑब्जेक्ट में विशेषताओं को जोड़ा जाता है जो इसे कहते हैं। इसलिए super()अनुवाद किया जाता है Personऔर फिर यदि आप छिपे हुए स्व को शामिल करते हैं, तो आपको उपरोक्त कोड सुगंधित मिलता है।

from abc import ABCMeta, abstractmethod
class Person(metaclass=ABCMeta):
    name = ""
    age = 0

    def __init__(self, personName, personAge):
        self.name = personName
        self.age = personAge

    @abstractmethod
    def showName(self):
        pass

    @abstractmethod
    def showAge(self):
        pass


class Man(Person):

    def __init__(self, name, height):
        self.height = height
        # Person.__init__(self, name, 10)
        super().__init__(name, 10)  # same as Person.__init__(self, name, 10)
        # basically used to call the superclass init . This is used incase you want to call subclass init
        # and then also call superclass's init.
        # Since there's a hidden self in the super's parameters, when it's is called,
        # the superclasses attributes are a part of the same object that was sent out in the super() method

    def showIdentity(self):
        return self.name, self.age, self.height

    def showName(self):
        pass

    def showAge(self):
        pass


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