सुपर का उपयोग करने का सही तरीका (तर्क पास करना)


100

इसलिए मैं पायथन के सुपर कॉन्सिडर्ड हार्मफुल का अनुसरण कर रहा था , और उनके उदाहरणों का परीक्षण करने के लिए गया।

हालाँकि, उदाहरण 1-3 , जिसे विभिन्न तर्कों की अपेक्षा करने वाले तरीकों को superसंभालने के दौरान कॉल करने का सही तरीका दिखाना __init__है, फ्लैट-आउट काम नहीं करता है।

यह वही है जो मुझे मिलता है:

~ $ python example1-3.py 
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Traceback (most recent call last):
  File "Download/example1-3.py", line 27, in <module>
    E(arg=10)
  File "Download/example1-3.py", line 24, in __init__
    super(E, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 14, in __init__
    super(C, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 4, in __init__
    super(A, self).__init__(*args, **kwargs)
  File "Download/example1-3.py", line 19, in __init__
    super(D, self).__init__(arg, *args, **kwargs)
  File "Download/example1-3.py", line 9, in __init__
    super(B, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters

ऐसा लगता है कि objectस्वयं दस्तावेज़ में उल्लिखित सर्वोत्तम प्रथाओं में से एक का उल्लंघन करता है, यही वह तरीका है जो उपयोग superकरना चाहिए *argsऔर स्वीकार करना चाहिए **kwargs।

अब, जाहिर है कि श्री नाइट ने अपने उदाहरणों पर काम करने की उम्मीद की है, तो क्या यह कुछ ऐसा है जिसे पायथन के हाल के संस्करणों में बदल दिया गया था? मैंने 2.6 और 2.7 की जाँच की, और यह दोनों पर विफल है।

तो इस समस्या से निपटने का सही तरीका क्या है?


2
मेरा पसंदीदा तरीका है: फ्लैट और साधारण वंशानुगत पदानुक्रम।
— मिलिमोस

19
आपको संतुलित दृश्य प्राप्त करने के लिए "पायथन के सुपर () सुपर" माना जाता है :) पढ़ना चाहिए :
— ब्योर्न पोलेक्स

@ BjörnPollex: धन्यवाद! आपका लिंक प्रश्न का उत्तर प्रदान करता है: आप "मूल वर्ग" जो से विरासत में मिली लिख सकते हैं object, और यह कॉल करने के लिए सुनिश्चित करती है object's __init__सही ढंग से।
— cha0site

5
ध्यान दें कि पायथन 2.5 पर किसी भी पैरामीटर __init__को objectचुपचाप अनदेखा कर देता है। यह पायथन 2.6 में बदल गया।
— विल्फ्रेड ह्यूजेस

1
@Wilfred: अरे, वास्तविक प्रश्न का उत्तर देने के लिए धन्यवाद! अब मुझे पता है कि निबंध क्यों पुराना है!
— cha0site

जवाबों:


104

कभी-कभी दो वर्गों में कुछ पैरामीटर नाम सामान्य हो सकते हैं। उस स्थिति में, आप कुंजी-मूल्य वाले जोड़े को बंद नहीं कर सकते **kwargsया उन्हें हटा नहीं सकते *args। इसके बजाय, आप एक Baseवर्ग को परिभाषित कर सकते हैं जो इसके विपरीत object, तर्कों को अवशोषित / अनदेखा करता है:

class Base(object):
    def __init__(self, *args, **kwargs): pass

class A(Base):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(Base):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(arg, *args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(arg, *args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(arg, *args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10)

पैदावार

MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B

ध्यान दें कि इसके लिए काम करने के लिए, BaseMRO में पारंगत वर्ग होना चाहिए।


4
Baseफोन नहीं करना चाहिए super(Base, self).__init__()?
— cha0site

4
इस काम के लिए, BaseMRO के अंत में आना चाहिए (को छोड़कर object)। कॉलिंग object.__init__कुछ भी नहीं करता है, इसलिए कॉल करना ठीक नहीं है super(Base, self).__init__()। वास्तव में, मुझे लगता है कि यह स्पष्ट हो सकता है super(Base, self).__init__()कि Baseलाइन के अंत में घर को ड्राइव करने के लिए शामिल न करें ।
— अनटुब

25

यदि आपके पास बहुत अधिक विरासत है (जो कि यहां मामला है) तो मैं आपको सभी मापदंडों का उपयोग करने के लिए पारित करने का सुझाव देता हूं **kwargs, और फिर popउन्हें उपयोग करने के ठीक बाद में (जब तक कि आपको ऊपरी कक्षाओं में उनकी आवश्यकता न हो)।

class First(object):
    def __init__(self, *args, **kwargs):
        self.first_arg = kwargs.pop('first_arg')
        super(First, self).__init__(*args, **kwargs)

class Second(First):
    def __init__(self, *args, **kwargs):
        self.second_arg = kwargs.pop('second_arg')
        super(Second, self).__init__(*args, **kwargs)

class Third(Second):
    def __init__(self, *args, **kwargs):
        self.third_arg = kwargs.pop('third_arg')
        super(Third, self).__init__(*args, **kwargs)

इस तरह की समस्याओं को हल करने का यह सबसे सरल तरीका है।

third = Third(first_arg=1, second_arg=2, third_arg=3)

6

जैसा कि पायथन के सुपर () सुपर में माना जाता है , एक तरीका यह है कि वर्ग को उन तर्कों को खाने की आवश्यकता होती है, और बाकी को पास करें। इस प्रकार, जब कॉल-चेन पहुंचता है object, तो सभी तर्क खाए गए हैं, और object.__init__बिना तर्कों के कहा जाएगा (जैसा कि यह उम्मीद करता है)। तो आपका कोड इस तरह दिखना चाहिए:

class A(object):
    def __init__(self, *args, **kwargs):
        print "A"
        super(A, self).__init__(*args, **kwargs)

class B(object):
    def __init__(self, *args, **kwargs):
        print "B"
        super(B, self).__init__(*args, **kwargs)

class C(A):
    def __init__(self, arg, *args, **kwargs):
        print "C","arg=",arg
        super(C, self).__init__(*args, **kwargs)

class D(B):
    def __init__(self, arg, *args, **kwargs):
        print "D", "arg=",arg
        super(D, self).__init__(*args, **kwargs)

class E(C,D):
    def __init__(self, arg, *args, **kwargs):
        print "E", "arg=",arg
        super(E, self).__init__(*args, **kwargs)

print "MRO:", [x.__name__ for x in E.__mro__]
E(10, 20, 30)

तो, किस बारे में E(arg = 10)? मुझे यह तरीका पसंद नहीं है, मुझे इसका उपयोग करने के लिए पहले से ही एमआरओ को जानना आवश्यक है। दूसरी विधि जहां मैं एक "रूट क्लास" लिखता हूं, जो विरासत में मिला objectहै, बहुत क्लीनर लगता है।
— cha0site

यह विधि उपयोगी है यदि फ़ंक्शन कहा जाता है, तो तर्क-नामों को साझा न करें। मैं मानता हूं कि मेरे पास ज्यादा व्यावहारिक अनुभव नहीं है super, इसलिए यह दृष्टिकोण वास्तव में सैद्धांतिक हो सकता है।
— ब्योर्न पोलेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.