2009-11-11 17 views
12

का उपयोग करके मैं किसी ऑब्जेक्ट को ओवरराइड करने के लिए किसी ऑब्जेक्ट को उप-वर्गीकृत कर रहा हूं जिसमें मैं कुछ कार्यक्षमता जोड़ना चाहता हूं। मैं इसे पूरी तरह से प्रतिस्थापित नहीं करना चाहता हूं या एक अलग नामित विधि जोड़ना चाहता हूं लेकिन विधि में वैकल्पिक तर्क जोड़कर सुपरक्लास विधि के अनुकूल हूं। क्या सुपरक्लास के सभी तर्कों को पार करने के लिए *args और **kwargs के साथ काम करना संभव है और फिर भी डिफ़ॉल्ट के साथ वैकल्पिक तर्क जोड़ना संभव है? मैं intuitively निम्नलिखित के साथ आया था, लेकिन यह काम नहीं करता है:एक ओवरराइड विधि में एक कीवर्ड तर्क जोड़कर और ** kwarg

class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, argopt2="foo", **kwargs): 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 
बेशक

मैं यह काम करने के लिए प्राप्त कर सकते हैं जब मैं स्पष्ट रूप से सुपर क्लास की विधि की सभी तर्कों जोड़ें:

class B(A): 
    def foo(self, arg1, arg2, argopt1="foo", argopt2="bar"): 
     print argopt2 
     A.foo(self, arg1, arg2, argopt1=argopt1) 

ऐसा करने का सही तरीका क्या है, क्या मुझे सभी ओवरराइड विधियों के तर्कों को जानना और स्पष्ट रूप से अवश्य कहना है?

उत्तर

10
class A(object): 
    def foo(self, arg1, arg2, argopt1="bar"): 
     print arg1, arg2, argopt1 

class B(A): 
    def foo(self, *args, **kwargs): 
     argopt2 = kwargs.get('argopt2', default_for_argopt2) 
     # remove the extra arg so the base class doesn't complain. 
     del kwargs['argopt2'] 
     print argopt2 
     A.foo(self, *args, **kwargs) 


b = B() 
b.foo("a", "b", argopt2="foo") 
+5

आप + डेल पाने के बजाए पॉप का उपयोग कर सकते हैं। – iny

+0

मैं हमेशा dict.pop के बारे में भूल जाता हूँ! –

+3

आपका तर्क 'keyError' के साथ विफल रहता है जब 'argopt2' पास नहीं होता है। 'Kwargs.pop ('argopt2', default_for_argopt2) का उपयोग करना इसे ठीक करने का सबसे आसान तरीका है। –

1

जब उपवर्गीकरण और अधिभावी तरीकों, एक हमेशा यह तय करना होगा अगर super() का उपयोग कर एक अच्छा विचार है, और this page कि लिए अच्छा है।

मैं नहीं कह रहा है कि super(), बचा जाना चाहिए की तरह लेख लेखक हो सकता है: मैं कह रहा हूँ कि super() कुछ बहुत महत्वपूर्ण prerequisits कि पालन किया जाना चाहिए है अगर आप super() वापस आने के लिए नहीं करना चाहते हैं और आपको काटा।

+0

http://fuhm.org/super-harmful/ एक अच्छा पढ़ा है। धन्यवाद, हस्ताक्षर परिवर्तन पर चेतावनी के लिए टेडी – unutbu

6

यह करने के लिए सही तरीका क्या है, मुझे पता है और स्पष्ट रूप से ओवरराइड तरीकों सभी तर्क राज्य है करते हैं?

आप सभी मामलों को कवर करना चाहते हैं (हमेशा चीजों को अपने तरीके से, जैसे करने के लिए के बजाय फोन करने वाले पर भरोसा करते हैं, हमेशा आप केवल अतिरिक्त तर्क द्वारा नाम से पारित कर दिया साथ कहते हैं, स्थिति से कभी नहीं) आप की क्या ज़रूरत है जिस विधि को आप ओवरराइड कर रहे हैं उसके हस्ताक्षर के बारे में बहुत सारे ज्ञान को कोड (या गतिशील रूप से खोजना) - शायद ही आश्चर्यजनक: विरासत युग्मन का एक मजबूत रूप है, और ओवरराइडिंग विधियां एक तरीका है जो युग्मन स्वयं प्रस्तुत करता है।

आप गतिशील inspect.getargspec के माध्यम से सुपर क्लास की विधि तर्क, आदेश सुनिश्चित करें कि आप इसे ठीक से फोन बनाने के लिए खोज सकता है ... लेकिन यह आत्मनिरीक्षण तकनीक मुश्किल हो सकता है अगर दो कक्षाएं बिल्कुल वही बात करने के लिए कोशिश कर रहे हैं (एक बार जब आप जानते हैं कि आपके सुपरक्लास की विधि *a और/या **kw स्वीकार करती है तो आप सभी प्रासंगिक तर्कों को ऊपर और उम्मीद से गुजरने के अलावा थोड़ा अधिक कर सकते हैं, उंगलियों के साथ पार हो जाने के बाद, अपस्ट्रीम विधि श्रृंखला अंततः एक ऐसे संस्करण को कॉल करने से पहले उचित घर-सफाई कर रही है जो काफी सहनशील नहीं है) ।

ऐसी कीमतें भुगतान करने योग्य हो सकती हैं जब आप एक रैपर तैयार कर रहे हैं जिसका अर्थ है कि विभिन्न प्रकार के हस्ताक्षरों के साथ कॉलबेल के लिए गतिशील रूप से लागू किया जाना चाहिए (विशेष रूप से जब सजावटी सेटिंग में आप आत्मनिरीक्षण की भारी लागत का भुगतान करने की व्यवस्था कर सकते हैं प्रति समारोह जो आप सजाने वाले हैं, न कि परिणामी रैपर को हर बार कहा जाता है)। ऐसा लगता है कि आपके जैसे मामले में एक सार्थक तकनीक होने की संभावना नहीं है, जहां आप बेहतर ढंग से जानते हैं कि आप क्या कर रहे हैं (उपclassing मजबूत युग्मन है: इसे अंधा कर रहा है निश्चित रूप से सलाह नहीं दी जाती है!), और इसलिए आप भी वर्तनी कर सकते हैं स्पष्ट रूप से तर्क।

हां, अगर सुपरक्लास का कोड भारी रूप से बदलता है (उदा।, विधि हस्ताक्षर बदलने के द्वारा), आपको उप-वर्ग को भी संशोधित करना होगा - वह विरासत की कीमत (भाग) है। कुल कीमत इतनी भारी है कि नई Go प्रोग्रामिंग भाषा पूरी तरह से इसके बिना पूरी तरह से करती है - को मजबूर करने के लिए prefer composition over inheritance पर उत्कृष्ट सलाह लागू करने के लिए। पाइथन में विरासत से पूरी तरह से रोकथाम सिर्फ अव्यवहारिक होगा, लेकिन इसे शांततापूर्वक और संयम में उपयोग करना (और जब आप करते हैं तो युग्मन के मामले में आप जो कीमत चुकानी पड़ेगी) उसे सलाह दी जाती है।

+0

+1। लेकिन मुझे लगता है कि एक अपवाद है: कन्स्ट्रक्टर के हस्ताक्षर को बदलना ठीक है। और प्रश्न में वर्णित समस्या कन्स्ट्रक्टर पर भी लागू होती है। –

संबंधित मुद्दे