2013-01-31 10 views
34

मैं अक्सर माता-पिता वर्ग के ओवरराइटिंग विधियों को ढूंढता हूं, और कभी यह तय नहीं कर सकता कि मुझे स्पष्ट पैरामीटर सूचीबद्ध करना चाहिए या केवल कंबल *args, **kwargs निर्माण का उपयोग करना चाहिए। क्या एक संस्करण दूसरे से बेहतर है? क्या कोई सर्वोत्तम अभ्यास है? मुझे क्या याद आ रहा है?विरासत सर्वोत्तम अभ्यास: * तर्क, ** kwargs या स्पष्ट रूप से पैरामीटर निर्दिष्ट करते हैं

class Parent(object): 

    def save(self, commit=True): 
     # ... 

class Explicit(Parent): 

    def save(self, commit=True): 
     super(Explicit, self).save(commit=commit) 
     # more logic 

class Blanket(Parent): 

    def save(self, *args, **kwargs): 
     super(Blanket, self).save(*args, **kwargs) 
     # more logic 

स्पष्ट संस्करण के कथित लाभ

  • अधिक स्पष्ट (अजगर की ज़ेन)
  • आसान समझ
  • समारोह मापदंडों आसानी से

कथित लाभ का पहुँचा कंबल varia NT

  • अधिक सूखी
  • माता पिता वर्ग आसानी से विनिमेय है
  • माता पिता विधि में मूलभूत मूल्यों की
  • परिवर्तन अन्य कोड को बिना छुए प्रचारित कर रहा है
+2

इसमें से बहुत कुछ इस बात पर निर्भर करता है कि आप जो उपclassing कर रहे हैं ...यदि उच्च श्रेणी है कि आप बेस क्लास के तरीकों के लिए अतिरिक्त kwargs (या कोई और करेंगे) जोड़ने जा रहे हैं, तो यह '** kwargs' के साथ चिपकने के लिए बहुत अधिक समझ में आता है। यदि यह संभव नहीं है, तो स्पष्ट रूप से निर्दिष्ट करने के लिए kwargs एक पठनीयता दृष्टिकोण से निश्चित रूप से बेहतर है। –

+0

ठीक है, आप निश्चित रूप से जानकारी फेंक रहे हैं। * स्पष्ट * और सभी की तुलना में स्पष्ट है। – kojiro

+2

आपके पास दो विकल्प हैं: 1) स्पष्ट रूप से पैरामीटर और * प्रतिबंधित * व्युत्पन्न कक्षाओं में हस्ताक्षर परिवर्तनों का नाम दें (अन्यथा 'सुपर' और एकाधिक विरासत के साथ अच्छा), या 2) '** kwargs' का उपयोग करें और विधियों के हस्ताक्षर को बदलने की अनुमति दें । किस का उपयोग किया जाना चाहिए शायद स्थिति पर निर्भर करता है। – Bakuriu

उत्तर

23

Liskov प्रतिस्थापन सिद्धांत

आम तौर पर आप आप विधि हस्ताक्षर व्युत्पन्न प्रकार में भिन्नता है नहीं करना चाहती। यदि आप व्युत्पन्न प्रकारों के उपयोग को स्वैप करना चाहते हैं तो इससे समस्याएं पैदा हो सकती हैं। इसे अक्सर Liskov Substitution Principle के रूप में जाना जाता है।

स्पष्ट हस्ताक्षर

एक ही समय में करने के लाभ मैं यह सही है अपने सभी तरीकों *args, **kwargs के हस्ताक्षर करने के लिए नहीं लगता। स्पष्ट हस्ताक्षर:

  • मदद अच्छा तर्क के नाम के माध्यम से
  • मदद विधि दस्तावेज़ के लिए निर्दिष्ट करने के जो आर्ग की आवश्यकता है और जो कर रहे हैं के द्वारा विधि दस्तावेज़ के लिए डिफ़ॉल्ट मान
  • अंतर्निहित मान्यता प्रदान की है (याद आ रही आवश्यक args स्पष्ट अपवाद फेंक)

चर लंबाई तर्क और युग्मन

अच्छे युग्मन अभ्यास के लिए परिवर्तनीय लंबाई तर्क गलती मत करो। माता-पिता वर्ग और व्युत्पन्न कक्षाओं के बीच एक निश्चित मात्रा में एकजुट होना चाहिए अन्यथा वे एक-दूसरे से संबंधित नहीं होंगे। संबंधित कोड के लिए यह सामान्य है कि परिणामस्वरूप युग्मन होता है जो एकजुटता के स्तर को दर्शाता है।

स्थान चर लंबाई तर्क चर लंबाई तर्कों की

उपयोग का उपयोग करने के अपने पहले विकल्प नहीं होना चाहिए। इसका उपयोग तब किया जाना चाहिए जब आपके पास कोई अच्छा कारण हो:

  • फ़ंक्शन रैपर को परिभाषित करना (यानी एक सजावटी)।
  • एक पैरामीट्रिक पॉलिमॉर्फिक फ़ंक्शन को परिभाषित करना।
  • जब तर्क जो आप ले सकते हैं वास्तव में पूरी तरह से परिवर्तनीय हैं (उदा। सामान्यीकृत डीबी कनेक्शन फ़ंक्शन)। डीबी कनेक्शन फ़ंक्शन आमतौर पर connection string को कई अलग-अलग रूपों में, एकल तर्क फ़ॉर्म में और बहु-तर्क फ़ॉर्म में लेते हैं। विभिन्न डेटाबेस के लिए विकल्पों के विभिन्न सेट भी हैं।
  • ...

आप कुछ गलत कर रहे हैं?

यदि आप पाते हैं कि आप अक्सर ऐसे तरीके बनाते हैं जो विभिन्न हस्ताक्षरों के साथ कई तर्क या व्युत्पन्न विधियां लेते हैं तो आपको एक बड़ा मुद्दा हो सकता है कि आप अपना कोड कैसे व्यवस्थित कर रहे हैं।

13

मेरे विकल्प होगा:

class Child(Parent): 

    def save(self, commit=True, **kwargs): 
     super(Child, self).save(commit, **kwargs) 
     # more logic 

यह *args और 0 से प्रतिबद्ध तर्क तक पहुंचने से बचाता हैऔर Parent:save परिवर्तनों के हस्ताक्षर (उदाहरण के लिए एक नया डिफ़ॉल्ट तर्क जोड़ना) में यह चीजें सुरक्षित रखती है।

अद्यतन: इस मामले में, * तर्क होने पर माता-पिता को नया स्थितित्मक तर्क जोड़ा जाता है तो * तर्क होने से परेशानी हो सकती है। मैं केवल **kwargs रखूंगा और डिफ़ॉल्ट मानों के साथ केवल नए तर्क प्रबंधित करूंगा। यह प्रचार करने के लिए त्रुटियों से बच जाएगा।

+1

मुझे विश्वास है कि यह सबसे अच्छा जवाब है, क्योंकि यह प्रश्न से उजागर आवश्यकताओं को संबोधित करता है। अर्थात्: भविष्य में माता-पिता को तर्क जोड़ने की संभावना बनाम स्पष्ट बनाम तर्क रखें। @dietbuddha द्वारा दिए गए उत्तर के बावजूद "अकादमिक" सही है, यह एक विकल्प प्रदान नहीं करता है जिसे अभ्यास में नियोजित किया जा सकता है, जब आप निश्चित रूप से नहीं जानते कि भविष्य में आपके कोड का भाग्य क्या होगा। यह जवाब उस पते को संबोधित करता है। –

+0

एलेक्स मार्टेलि द्वारा प्रदान किया गया उत्तर [इस SO थ्रेड में] (http://stackoverflow.com/questions/1098549/proper-way-to-use-kwargs-in-python) इस विषय के बारे में अधिक जानकारी है। –

+0

जिस तरह से आप इसे लिखते हैं, आपको यह दर्शाता है कि माता-पिता के हस्ताक्षर में '** kwargs' है जो प्रश्न के उदाहरण में मामला नहीं है। –

4

आपको विश्वास है कि बाल हस्ताक्षर रखेंगे कर रहे हैं, निश्चित रूप से स्पष्ट दृष्टिकोण बेहतर है, लेकिन जब बाल हस्ताक्षर बदल जाएगा मैं व्यक्तिगत रूप से दोनों दृष्टिकोण का उपयोग करना पसंद:

class Parent(object): 
    def do_stuff(self, a, b): 
     # some logic 

class Child(Parent): 
    def do_stuff(self, c, *args, **kwargs): 
     super(Child, self).do_stuff(*args, **kwargs) 
     # some logic with c 

इस तरह, में परिवर्तन हस्ताक्षर बच्चे में काफी पठनीय हैं, जबकि मूल हस्ताक्षर माता-पिता में काफी पठनीय है।

मेरी राय में यह एक बेहतर तरीका है जब आपके पास एकाधिक विरासत है, क्योंकि super पर कॉल करने पर कुछ बार घृणित होता है जब आपके पास तर्क और क्वॉर्ग नहीं होते हैं।

इसके लायक होने के लिए, यह कुछ पाइथन libs और ढांचे (Django, Tornado, अनुरोध, Markdown, कुछ नाम) में भी पसंदीदा तरीका है। हालांकि किसी को ऐसी चीजों पर अपने विकल्पों का आधार नहीं लेना चाहिए, मैं केवल यह कह रहा हूं कि यह दृष्टिकोण काफी व्यापक है।

2

मैं स्पष्ट तर्क पसंद करता हूं क्योंकि ऑटो पूर्ण आपको फ़ंक्शन कॉल करते समय फ़ंक्शन के विधि हस्ताक्षर को देखने की अनुमति देता है।

3

नहीं वास्तव में एक जवाब है, लेकिन अधिक एक तरफ ध्यान दें:

class Parent(object): 

    default_save_commit=True 
    def save(self, commit=default_save_commit): 
     # ... 

class Derived(Parent): 

    def save(self, commit=Parent.default_save_commit): 
     super(Derived, self).save(commit=commit) 

हालांकि: यदि आप सच में, सच माता पिता वर्ग के लिए डिफ़ॉल्ट मान बच्चे कक्षाओं आप की तरह कुछ कर सकते हैं करने के लिए उगाया जाता है यह सुनिश्चित करना चाहते हैं मुझे यह मानना ​​है कि यह बहुत बदसूरत दिखता है और अगर मैं महसूस करता हूं कि मुझे वास्तव में इसकी ज़रूरत है तो मैं इसका इस्तेमाल करूंगा।

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