2012-01-23 13 views
52

तो मैं Python's Super Considered Harmful का पालन कर रहा था, और अपने उदाहरणों का परीक्षण करने गया।सुपर (तर्क गुजरने) का उपयोग करने का सही तरीका

हालांकि, Example 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

मेरा पसंदीदा तरीका है: फ्लैट और सरल विरासत पदानुक्रम। – millimoose

+14

आपको एक संतुलित दृश्य प्राप्त करने के लिए ["पायथन के सुपर() को सुपर"] (http://rhettinger.wordpress.com/2011/05/26/super-cononsidered-super/) भी पढ़ना चाहिए :) –

+0

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

उत्तर

55

कभी-कभी दो कक्षाओं में कुछ पैरामीटर नाम सामान्य होते हैं। उस स्थिति में, आप **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 

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

+2

'आधार' कॉल नहीं होना चाहिए सुपर (बेस, स्वयं) .__ init __() '? – cha0site

+2

इसके लिए काम करने के लिए, 'बेस' एमआरओ के अंत में आना चाहिए (' ऑब्जेक्ट' को छोड़कर)। कॉलिंग 'ऑब्जेक्ट .__ init__' कुछ भी नहीं करता है, इसलिए ठीक है' सुपर (बेस, सेल्फ) .__ init __() 'को कॉल करना ठीक है। असल में, मुझे लगता है कि यह स्पष्ट हो सकता है कि 'सुपर (बेस, स्वयं) .__ init __() 'को घर पर ड्राइव करने के लिए' बेस 'लाइन का अंत है। – unutbu

5

जैसा कि Python's super() considered super में बताया गया है, एक तरीका यह है कि कक्षा को आवश्यक तर्कों को खाने के लिए, और बाकी को पास करें। इस प्रकार, जब कॉल-चेन 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) 
+0

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

+0

यह विधि उपयोगी है अगर बुलाए गए फ़ंक्शन तर्क-नाम साझा नहीं करते हैं। मैं मानता हूं कि मेरे पास 'सुपर' के साथ बहुत व्यावहारिक अनुभव नहीं है, इसलिए यह दृष्टिकोण वास्तव में सैद्धांतिक हो सकता है। –

14

आप inheritence का एक बहुत है करने के लिए जा रहे हैं मैं सुझाव है कि आप **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) 
संबंधित मुद्दे