2009-06-19 22 views
74

मान लीजिए आप निम्नलिखित स्थितिपायथन में विरासत का क्या मतलब है?

#include <iostream> 

class Animal { 
public: 
    virtual void speak() = 0; 
}; 

class Dog : public Animal { 
    void speak() { std::cout << "woff!" <<std::endl; } 
}; 

class Cat : public Animal { 
    void speak() { std::cout << "meow!" <<std::endl; } 
}; 

void makeSpeak(Animal &a) { 
    a.speak(); 
} 

int main() { 
    Dog d; 
    Cat c; 
    makeSpeak(d); 
    makeSpeak(c); 
} 

आप देख सकते हैं है, makeSpeak एक नियमित है कि एक सामान्य पशु वस्तु को स्वीकार करता है। इस मामले में, पशु जावा इंटरफेस के समान ही है, क्योंकि इसमें केवल शुद्ध वर्चुअल विधि है। मेकस्पीक पशु की प्रकृति को नहीं जानता है जो इसे पारित किया जाता है। यह सिर्फ सिग्नल को "बोलता है" भेजता है और कॉल करने के लिए किस विधि का ख्याल रखने के लिए देर से बाध्यकारी छोड़ देता है: या तो बिल्ली :: बोलें() या कुत्ता :: बोलें()। इसका मतलब यह है कि, जहां तक ​​मेकस्पीक का संबंध है, ज्ञान का वास्तव में पारित होने का ज्ञान अप्रासंगिक है।

लेकिन पायथन के बारे में क्या? चलिए पाइथन में एक ही मामले के लिए कोड देखते हैं। कृपया ध्यान दें कि मैं एक पल के लिए सी करने के लिए संभव के रूप में समान होने की कोशिश ++ मामला:

class Animal(object): 
    def speak(self): 
     raise NotImplementedError() 

class Dog(Animal): 
    def speak(self): 
     print "woff!" 

class Cat(Animal): 
    def speak(self): 
     print "meow" 

def makeSpeak(a): 
    a.speak() 

d=Dog() 
c=Cat() 
makeSpeak(d) 
makeSpeak(c) 

अब, इस उदाहरण में आप एक ही रणनीति को देखते हैं। आप कुत्तों और बिल्लियों दोनों जानवरों की पदानुक्रमिक अवधारणा का लाभ उठाने के लिए विरासत का उपयोग करते हैं। लेकिन पायथन में, इस पदानुक्रम की कोई आवश्यकता नहीं है। यह समान रूप से अच्छी तरह से काम करता है

class Dog: 
    def speak(self): 
     print "woff!" 

class Cat: 
    def speak(self): 
     print "meow" 

def makeSpeak(a): 
    a.speak() 

d=Dog() 
c=Cat() 
makeSpeak(d) 
makeSpeak(c) 

पायथन में आप किसी भी वस्तु को "बोलने" संकेत भेज सकते हैं। यदि वस्तु इसके साथ सौदा करने में सक्षम है, तो इसे निष्पादित किया जाएगा, अन्यथा यह एक अपवाद उठाएगा। मान लीजिए कि आप दोनों कोडों में एक क्लास एयरप्लेन जोड़ते हैं, और स्पीक बनाने के लिए एक एयरप्लेन ऑब्जेक्ट सबमिट करते हैं। सी ++ मामले में, यह संकलित नहीं होगा, क्योंकि विमान पशु का व्युत्पन्न वर्ग नहीं है। पायथन मामले में, यह रनटाइम पर एक अपवाद उठाएगा, जो एक अपेक्षित व्यवहार भी हो सकता है।

दूसरी ओर, मान लीजिए कि आप विधि विधि() के साथ एक MouthOfTruth क्लास जोड़ते हैं। सी ++ मामले में, आपको या तो अपने पदानुक्रम को दोबारा बदलना होगा, या आपको मुथऑफट्रूथ ऑब्जेक्ट्स को स्वीकार करने के लिए एक अलग मेक स्पीक विधि को परिभाषित करना होगा, या जावा में आप व्यवहार को कैनस्पीकआईफेस में निकाल सकते हैं और प्रत्येक के लिए इंटरफेस को कार्यान्वित कर सकते हैं। कई समाधान हैं ...

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

तो अंत में, प्रश्न खड़ा है: पायथन में विरासत का बिंदु क्या है?

संपादित करें: बहुत ही रोचक उत्तरों के लिए धन्यवाद। दरअसल आप इसे कोड पुन: उपयोग के लिए उपयोग कर सकते हैं, लेकिन कार्यान्वयन का पुन: उपयोग करते समय मैं हमेशा सावधान रहता हूं। आम तौर पर, मैं बहुत उथले विरासत पेड़ या कोई पेड़ नहीं करता हूं, और यदि कोई कार्यक्षमता आम है तो मैं इसे एक सामान्य मॉड्यूल दिनचर्या के रूप में पुनः प्रतिक्रिया देता हूं और फिर इसे प्रत्येक ऑब्जेक्ट से कॉल करता हूं। मुझे परिवर्तन का एक बिंदु होने का लाभ दिखाई देता है (उदाहरण के लिए, कुत्ते, बिल्ली, मूस और अन्य में जोड़ने के बजाय, मैं सिर्फ पशु में जोड़ता हूं, जो विरासत का मूल लाभ है), लेकिन आप इसे प्राप्त कर सकते हैं एक प्रतिनिधिमंडल श्रृंखला (उदाहरण के लिए एक ला जावास्क्रिप्ट)। मैं दावा नहीं कर रहा हूं कि यह बेहतर है, हालांकि, एक और तरीका है।

मुझे इस संबंध में a similar post भी मिला।

+18

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

+9

वास्तव में मैंने कहा "मैं दावा नहीं कर रहा हूं कि यह बेहतर है;)" –

+4

"मुझे अभी तक पाइथन में विरासत का उपयोग करने का एक कारण नहीं मिला है" ... यकीन है कि "मेरा समाधान बेहतर है"। –

उत्तर

79

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

मैं दो उदाहरण दे सकता हूं कि मेरी राय में विरासत सही दृष्टिकोण कहां है, मुझे यकीन है कि और भी कुछ हैं।

सबसे पहले, अगर आप बुद्धिमानी से कोड करते हैं, तो आपका मेकस्पीक फ़ंक्शन यह सत्यापित करना चाहता है कि उसका इनपुट वास्तव में एक पशु है, न केवल वह "यह बात कर सकता है", इस मामले में सबसे सुंदर तरीका विरासत का उपयोग करना होगा। दोबारा, आप इसे अन्य तरीकों से कर सकते हैं, लेकिन यह ऑब्जेक्ट उन्मुख डिजाइन की सुंदरता विरासत के साथ है - आपका कोड "वास्तव में" जांच करेगा कि इनपुट "पशु" है या नहीं।

दूसरा, और स्पष्ट रूप से अधिक सरल, Encapsulation - वस्तु उन्मुख डिजाइन का एक और अभिन्न हिस्सा है। यह प्रासंगिक हो जाता है जब पूर्वजों के पास डेटा सदस्य और/या गैर-अमूर्त विधियां होती हैं। निम्नलिखित मूर्खतापूर्ण उदाहरण है, जिसमें पूर्वज एक समारोह (speak_twice) है ले लो उस समय के सार समारोह का आह्वान है कि:

class Animal(object): 
    def speak(self): 
     raise NotImplementedError() 

    def speak_twice(self): 
     self.speak() 
     self.speak() 

class Dog(Animal): 
    def speak(self): 
     print "woff!" 

class Cat(Animal): 
    def speak(self): 
     print "meow" 

मान लिया जाये कि "speak_twice" है एक महत्वपूर्ण विशेषता है, तुम नहीं दोनों कुत्ता में यह कोड करने के लिए करना चाहते हैं और बिल्ली, और मुझे यकीन है कि आप इस उदाहरण को extrapolate कर सकते हैं। निश्चित रूप से, आप एक पाइथन स्टैंड-अलोन फ़ंक्शन को कार्यान्वित कर सकते हैं जो कुछ बतख-टाइप ऑब्जेक्ट को स्वीकार करेगा, जांच करें कि इसमें एक स्पीच फ़ंक्शन है या इसे दो बार बुलाता है, लेकिन यह दोनों गैर-सुरुचिपूर्ण और पॉइंट नंबर 1 याद करता है (यह एक जानवर को मान्य करता है)। इससे भी बदतर, और Encapsulation उदाहरण को मजबूत करने के लिए, क्या होगा अगर वंशज वर्ग में सदस्य कार्य "speak_twice" का उपयोग करना चाहता था?

यह उदाहरण "number_of_legs" कि "print_number_of_legs" तरह पूर्वज में गैर सार तरीके से प्रयोग किया जाता है के लिए भी स्पष्ट पूर्वज वर्ग एक डेटा सदस्य है अगर हो जाता है, है, लेकिन वंशज वर्ग 'निर्माता में शुरू किया जाता है (उदाहरण के लिए कुत्ते के साथ प्रारंभ होगा 4 जबकि सांप इसे 0 के साथ शुरू करेगा)।

फिर से, मुझे यकीन है कि अंतहीन उदाहरण हैं, लेकिन मूल रूप से ठोस वस्तु उन्मुख डिजाइन पर आधारित प्रत्येक (बड़े पर्याप्त) सॉफ़्टवेयर को विरासत की आवश्यकता होगी। अजगर में

+3

पहले मामले के लिए, इसका मतलब यह होगा कि आप व्यवहार के बजाय प्रकारों की जांच कर रहे हैं, जो कि अजीब तरह का है। दूसरे मामले के लिए, मैं सहमत हूं, और आप मूल रूप से "ढांचे" दृष्टिकोण कर रहे हैं। आप स्पीच_टवाइस के कार्यान्वयन को रीसाइक्लिंग कर रहे हैं, न केवल इंटरफेस, बल्कि ओवरराइडिंग के लिए, जब आप पाइथन पर विचार करते हैं तो आप विरासत के बिना जी सकते हैं। –

+9

आप कक्षाओं और कार्यों की तरह कई चीजों के बिना जी सकते हैं, लेकिन सवाल यह है कि कोड को महान बनाता है। मुझे लगता है कि विरासत करता है। –

+0

@ स्टेफानो बोरीनी - ऐसा लगता है कि आप बहुत "नियम-आधारित" दृष्टिकोण ले रहे हैं। पुराने cliche हालांकि सच है: वे टूटा हुआ था।:-) –

8

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

+3

की अवधारणा का एहसास हुआ है चुनिंदा ओवरराइडिंग विरासत का कारण है। यदि आप सबकुछ ओवरराइड करने जा रहे हैं, तो यह एक अजीब विशेष मामला है। –

+0

सब कुछ ओवरराइड कौन करेगा? आप पाइथन के बारे में सोच सकते हैं जैसे कि सभी विधियां सार्वजनिक हैं और वर्चुअल – bashmohandes

+1

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

0

वर्ग मूल रूप से सिर्फ कार्य करता है और डेटा का एक समूह समूहीकरण के तरीके हैं .. वे सी में कक्षाओं के लिए अलग ++ और इस तरह के हैं ..

मैं ज्यादातर सुपर के तरीके अधिभावी के लिए इस्तेमाल किया विरासत देखा है कक्षा। उदाहरण के लिए, शायद विरासत का एक और अधिक Python'ish उपयोग होगा ..

from world.animals import Dog 

class Cat(Dog): 
    def speak(self): 
     print "meow" 
पाठ्यक्रम बिल्लियों के

कुत्ते का एक प्रकार नहीं हैं, लेकिन मैं इस (तृतीय पक्ष) Dog वर्ग जो पूरी तरह से काम करता है, छोड़करspeak विधि जिसे मैं ओवरराइड करना चाहता हूं - यह पूरे वर्ग को फिर से कार्यान्वित करने से बचाता है, बस यह मेयो। फिर, CatDog का एक प्रकार नहीं है, लेकिन एक बिल्ली विशेषताओं का एक बहुत वारिस करता है, जबकि ..

एक बहुत बेहतर (व्यावहारिक) एक विधि या विशेषता अधिभावी का उदाहरण है कि कैसे आप urllib के लिए उपयोगकर्ता-एजेंट बदल रहा है ।आप मूल रूप से urllib.FancyURLopener उपवर्ग और संस्करण विशेषता (from the documentation) बदलने के लिए:

import urllib 

class AppURLopener(urllib.FancyURLopener): 
    version = "App/1.7" 

urllib._urlopener = AppURLopener() 

एक और तरीके से अपवाद उपयोग किया जाता है, अपवाद के लिए है जब विरासत एक अधिक "उचित" तरह से इस्तेमाल किया जाता है:

class AnimalError(Exception): 
    pass 

class AnimalBrokenLegError(AnimalError): 
    pass 

class AnimalSickError(AnimalError): 
    pass 

.. इसके बाद आप AnimalError को प्राप्त करने वाले सभी अपवादों को पकड़ने के लिए पकड़ सकते हैं, या AnimalBrokenLegError

+6

में सुरुचिपूर्ण क्यों नहीं था ... मैं आपके पहले उदाहरण से थोड़ा उलझन में हूं। आखिरी बार मैंने जांच की, बिल्लियों एक प्रकार का कुत्ता नहीं है, इसलिए मुझे यकीन नहीं है कि आप किस रिश्ते को प्रदर्शित करने की कोशिश कर रहे हैं। :-) –

+1

आप लिस्कोव सिद्धांत से गड़बड़ कर रहे हैं: बिल्ली एक कुत्ता नहीं है। इस मामले में उपयोग करना ठीक हो सकता है, लेकिन अगर कुत्ता वर्ग बदलता है और मिलता है, उदाहरण के लिए, एक "लीड" फ़ील्ड, जो बिल्लियों के लिए मूर्ख है? –

+1

यदि कोई पशु बेस-क्लास नहीं है, तो आपका विकल्प पूरी चीज को फिर से लागू करना है .. मैं यह नहीं कह रहा हूं कि यह सबसे अच्छा अभ्यास है (यदि कोई पशु बेस-क्लास है, इसका उपयोग करें), लेकिन यह काम करता है और आमतौर पर इसका उपयोग किया जाता है (उदाहरण के अनुसार, urlib के उपयोगकर्ता-एजेंट को बदलने का यह अनुशंसित तरीका है) – dbr

5

सी ++/जावा/आदि में, पॉलिमॉर्फिज्म विरासत के कारण होता है। उस ग़लत विश्वास को छोड़ दें, और गतिशील भाषाएं आपके लिए खुली हैं।

अनिवार्य रूप से, पायथन में कोई इंटरफ़ेस नहीं है "समझें कि कुछ विधियां कॉल करने योग्य हैं"। सुंदर हाथ-लहरदार और अकादमिक ध्वनि, नहीं? इसका मतलब है कि क्योंकि आप "बोलते" कहते हैं, आप स्पष्ट रूप से उम्मीद करते हैं कि ऑब्जेक्ट में "बोलने" विधि होनी चाहिए। सरल, हुह? यह बहुत Liskov-ian है कि एक वर्ग के उपयोगकर्ता अपने इंटरफेस को परिभाषित करते हैं, एक अच्छी डिजाइन अवधारणा जो आपको स्वस्थ टीडीडी में ले जाती है।

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

6

मुझे लगता है कि यह इस तरह अमूर्त उदाहरण के साथ एक सार्थक, ठोस जवाब देने के लिए बहुत मुश्किल है ...

आसान बनाने के लिए, वहाँ विरासत के दो प्रकार हैं। यदि आपको कार्यान्वयन का वारिस करने की आवश्यकता है, तो पाइथन स्थिर रूप से टाइप की गई ओओ भाषाओं जैसे सी ++ से अलग नहीं है।

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

ऐसे मामले हैं जहां इंटरफेस के लिए विरासत का उपयोग पायथन में किया जाता है, उदाहरण के लिए प्लग-इन आदि के लिए ... उन मामलों के लिए, पायथन 2.5 और नीचे के "अंतर्निहित" सुरुचिपूर्ण दृष्टिकोण और कई बड़े ढांचे की कमी है अपने स्वयं के समाधान डिजाइन (ज़ोप, ट्रैक, ट्विस्टर)। पायथन 2.6 और ऊपर ABC classes to solve this है।

9

पायथन में विरासत किसी और चीज़ की तुलना में अधिक सुविधा है। मुझे लगता है कि यह "डिफ़ॉल्ट व्यवहार" के साथ कक्षा प्रदान करने के लिए सबसे अच्छा उपयोग किया जाता है।

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

11

पायथन में विरासत कोड पुन: उपयोग के बारे में है। बेस क्लास में सामान्य कार्यक्षमता को फैक्टोरिज करें, और व्युत्पन्न कक्षाओं में विभिन्न कार्यक्षमता लागू करें।

1

आप पाइथन में और अधिकतर किसी भी अन्य भाषा में विरासत प्राप्त कर सकते हैं। यह कोड पुन: उपयोग और कोड सरलीकरण के बारे में सब कुछ है।

बस एक अर्थपूर्ण चाल है, लेकिन अपनी कक्षाओं और आधार वर्गों के निर्माण के बाद, आपको यह भी पता नहीं होना चाहिए कि आप अपने ऑब्जेक्ट के साथ क्या कर सकते हैं यह देखने के लिए कि आप इसे कर सकते हैं या नहीं।

कहो आप d जो एक कुत्ता है कि पशु subclassed है।

command = raw_input("What do you want the dog to do?") 
if command in dir(d): getattr(d,command)() 

यदि जो भी उपयोगकर्ता टाइप किया गया है, तो कोड उचित विधि चलाएगा।

इस का उपयोग करके आप स्तनपायी/सरीसृप/बर्ड संकर कुरूपता आप चाहते हैं के किसी भी संयोजन बनाने के लिए, और अब आप इसे कहते हैं कर सकते हैं 'बार्क' उड़ान भरने और उसकी कांटेदार जीभ चिपके हुए और यह ठीक से संभाल लेंगे! इसके साथ मजे करो!

1

मुझे विरासत में बहुत अधिक बिंदु नहीं दिख रहा है।

हर बार जब मैंने कभी भी वास्तविक प्रणालियों में विरासत का उपयोग किया है, तो मुझे जला दिया गया क्योंकि इससे निर्भरता के उलझन वाले वेब का कारण बन गया, या मुझे बस समय में एहसास हुआ कि मैं इसके बिना बहुत बेहतर होगा। अब, मैं जितना संभव हो उससे बचें। मैं इसके लिए कभी भी उपयोग नहीं करता हूं।

class Repeat: 
    "Send a message more than once" 
    def __init__(repeat, times, do): 
     repeat.times = times 
     repeat.do = do 

    def __call__(repeat): 
     for i in xrange(repeat.times): 
      repeat.do() 

class Speak: 
    def __init__(speak, animal): 
     """ 
     Check that the animal can speak. 

     If not we can do something about it (e.g. ignore it). 
     """ 
     speak.__call__ = animal.speak 

    def twice(speak): 
     Repeat(2, speak)() 

class Dog: 
    def speak(dog): 
     print "Woof" 

class Cat: 
    def speak(cat): 
     print "Meow" 

>>> felix = Cat() 
>>> Speak(felix)() 
Meow 

>>> fido = Dog() 
>>> speak = Speak(fido) 
>>> speak() 
Woof 

>>> speak.twice() 
Woof 

>>> speak_twice = Repeat(2, Speak(felix)) 
>>> speak_twice() 
Meow 
Meow 

जेम्स गोसलिंग एक बार एक संवाददाता सम्मेलन तर्ज पर एक सवाल पर कहा गया था: "क्या आप वापस जाएँ और अलग ढंग से जावा कर सकता है, तो आप बाहर छोड़ना होगा"। उनकी प्रतिक्रिया "कक्षाएं" थी, जिनके लिए हंसी थी। हालांकि, वह गंभीर था और समझाया कि वास्तव में, यह कक्षाएं नहीं थीं जो समस्या थी लेकिन विरासत थीं।

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

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

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

ऊपर कोड की तरह की चिंताओं का उचित जुदाई, गोंद तरीकों की आवश्यकता नहीं है, के रूप में हर कदम वास्तव में मूल्य जोड़ने है, तो वे वास्तव में 'गोंद' सब पर तरीकों नहीं कर रहे हैं (अगर वे उपयोगी नहीं होते डिजाइन त्रुटिपूर्ण है)।

यह इस करने पर निर्भर करता:

  • पुन: प्रयोज्य कोड के लिए, प्रत्येक वर्ग के केवल एक बात करना चाहिए (और यह अच्छी तरह से करते हैं)।

  • विरासत उन वर्गों को बनाता है जो एक से अधिक चीज़ करते हैं, क्योंकि वे पैरेंट कक्षाओं के साथ मिश्रित हैं।

  • इसलिए, विरासत का उपयोग कक्षाओं को पुन: उपयोग करने में कठोर बनाता है।

5

यह विरासत नहीं कर रहा है कि बतख टाइपिंग व्यर्थ बनाता है, यह इंटरफेस है - एक है कि आप एक सब सार पशु वर्ग बनाने में चुना है की तरह।

यदि आपने एक पशु वर्ग का उपयोग किया था जो इसके वंशजों के उपयोग के लिए कुछ वास्तविक व्यवहार पेश करता है, तो कुत्ते और बिल्ली वर्गों ने कुछ अतिरिक्त व्यवहार पेश किए हैं, दोनों वर्गों के लिए एक कारण होगा। यह केवल पूर्वजों के वर्ग के मामले में है जो वंश के वर्गों को कोई वास्तविक कोड नहीं दे रहा है कि आपका तर्क सही है।

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

1

एक और छोटा मुद्दा यह है कि ओप का 3 वां उदाहरण है, आप isinstance() को कॉल नहीं कर सकते हैं। उदाहरण के लिए, एक और ऑब्जेक्ट में अपना 3 वां उदाहरण पारित करना और "पशु" एक कॉल टाइप करें, उस पर बात करें। यदि आप ऐसा करते हैं तो आपको कुत्ते के प्रकार, बिल्ली के प्रकार, और इसी तरह की जांच नहीं करनी होगी। निश्चित नहीं है कि देर से बाध्यकारी होने के कारण, उदाहरण जांच वास्तव में "पायथनिक" है। लेकिन फिर आपको कुछ तरीकों को लागू करना होगा कि AnimalControl ट्रक में चीज़बर्गर प्रकार फेंकने की कोशिश नहीं करता है, क्योंकि चीज़बर्गर्स बात नहीं करते हैं।

class AnimalControl(object): 
    def __init__(self): 
     self._animalsInTruck=[] 

    def catachAnimal(self,animal): 
     if isinstance(animal,Animal): 
      animal.speak() #It's upset so it speak's/maybe it should be makesNoise 
      if not self._animalsInTruck.count <=10: 
       self._animalsInTruck.append(animal) #It's then put in the truck. 
      else: 
       #make note of location, catch you later... 
     else: 
      return animal #It's not an Animal() type/maybe return False/0/"message" 
संबंधित मुद्दे