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


83

मान लीजिए कि आपके पास निम्न स्थिति है

#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);
}

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

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

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)

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

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

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

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

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

मुझे इस संबंध में एक समान पोस्ट भी मिली ।


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

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

4
"मुझे अजगर में वंशानुक्रम का उपयोग करने का एक भी कारण अभी तक नहीं मिला है" ... निश्चित रूप से लगता है कि "मेरा समाधान बेहतर है"।
एस.लॉट

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

2
वास्तविक-विश्व कर व्यवस्थाएँ वस्तु-उन्मुखता के उदाहरणों के लिए एक अच्छा आधार हैं।
अपाला

जवाबों:


81

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

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

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

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

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

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


3
पहले मामले के लिए, इसका मतलब यह होगा कि आप व्यवहार के बजाय प्रकारों की जांच कर रहे हैं, जो कि एक प्रकार का अप्राकृतिक है। दूसरे मामले के लिए, मैं सहमत हूं, और आप मूल रूप से "रूपरेखा" दृष्टिकोण कर रहे हैं। आप केवल इंटरफ़ेस ही नहीं बल्कि Speak_twice के कार्यान्वयन को भी पुनर्चक्रित कर रहे हैं, जब आप अजगर मानते हैं तो आप विरासत के बिना रह सकते हैं।
स्टेफानो बोरीनी

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

@Stefano Borini - ऐसा लगता है कि आप बहुत "नियम-आधारित" दृष्टिकोण ले रहे हैं। पुराने क्लिच हालांकि सच है: उन्हें तोड़ा गया। :-)
जेसन बेकर

@ जेसन बेकर - मुझे नियम पसंद हैं क्योंकि वे अनुभव से प्राप्त ज्ञान की रिपोर्ट करते हैं (उदाहरण के लिए गलतियाँ), लेकिन मुझे रचनात्मकता पसंद नहीं है कि उनके द्वारा बाधा डाली जाए। इसलिए मैं आपके कथन से सहमत हूं।
स्टेफानो बोरीनी

1
मुझे यह उदाहरण इतना स्पष्ट नहीं लगता है - जानवरों, कारों और आकार के उदाहरण वास्तव में उन डिक्यूशन के लिए चूसते हैं :) केवल एक चीज जो आईएमएचओ के लिए मायने रखती है कि क्या आप कार्यान्वयन को विरासत में लेना चाहते हैं या नहीं। यदि हां, तो अजगर में नियम वास्तव में जावा / सी ++ के समान हैं; अंतर ज्यादातर वंशानुक्रम के लिए इंटरफेस के लिए है। उस मामले में, बतख-टाइपिंग अक्सर समाधान होता है - विरासत से बहुत अधिक।
डेविड कुर्नापेउ

12

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


11

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

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


8

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


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

1
कौन सब कुछ ओवरराइड करेगा? आप अजगर के बारे में सोच सकते हैं जैसे सभी तरीके सार्वजनिक और आभासी हैं
बशमोहनदेस

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

7

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

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

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

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


6

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

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

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


5

C ++ / Java / etc में, बहुरूपता वंशानुक्रम के कारण होता है। उस गलत धारणा को त्याग दें, और गतिशील भाषाएं आपके लिए खुल जाती हैं।

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

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


2

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

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

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

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

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

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

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

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

यह इसके लिए उबलता है:

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

  • वंशानुक्रम कक्षाएं बनाता है जो एक से अधिक कार्य करते हैं, क्योंकि वे मूल कक्षाओं के साथ मिश्रित होते हैं।

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


1

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

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

मान लीजिए कि आपके पास एक ऐसा कुत्ता है जो एनिमल को उपवर्गित करता है।

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

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

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


1

एक और छोटा बिंदु यह है कि op का 3'rd उदाहरण है, आप इसे आइंस्टीन () नहीं कह सकते। उदाहरण के लिए अपने 3'rd उदाहरण को किसी अन्य ऑब्जेक्ट पर ले जाना और "एनिमल" टाइप करना, इस पर बोलता है। यदि आप ऐसा नहीं करते हैं तो आपको कुत्ते के प्रकार, बिल्ली के प्रकार, और इसी तरह की जाँच करनी होगी। निश्चित नहीं है कि अगर उदाहरण की जाँच वास्तव में "पायथोनिक" है, तो देर से बाध्यकारी होने के कारण। लेकिन फिर आपको किसी तरह से लागू करना होगा कि 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"

0

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

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

from world.animals import Dog

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

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

एक विधि या विशेषता को ओवरराइड करने का एक बेहतर (व्यावहारिक) उदाहरण है कि आप उपयोगकर्ता-एजेंट को urllib के लिए कैसे बदलते हैं। आप मूल रूप से उप- urllib.FancyURLopenerसंस्करण ( प्रलेखन से ) संस्करण विशेषता को बदलते हैं :

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.