python - पायथन में सार बेस क्लास का उपयोग क्यों करें?




abstract-class abc (3)

लघु संस्करण

एबीसी ग्राहकों और लागू कक्षाओं के बीच एक उच्च स्तर का अर्थपूर्ण अनुबंध प्रदान करता है।

दीर्घ संस्करण

कक्षा और उसके कॉलर्स के बीच एक अनुबंध है। कक्षा कुछ चीजों को करने का वादा करती है और कुछ गुण हैं।

अनुबंध के लिए अलग-अलग स्तर हैं।

बहुत कम स्तर पर, अनुबंध में विधि या उसके पैरामीटर की संख्या शामिल हो सकती है।

स्थिर रूप से टाइप की गई भाषा में, वह अनुबंध वास्तव में संकलक द्वारा लागू किया जाएगा। पायथन में, आप यह पुष्टि करने के लिए ईएएफपी या आत्मनिरीक्षण का उपयोग कर सकते हैं कि अज्ञात वस्तु इस अपेक्षित अनुबंध को पूरा करती है।

लेकिन अनुबंध में उच्च स्तर, अर्थपूर्ण वादे भी हैं।

उदाहरण के लिए, यदि कोई __str__() विधि है, तो यह ऑब्जेक्ट का एक स्ट्रिंग प्रस्तुति वापस करने की उम्मीद है। यह ऑब्जेक्ट की सभी सामग्री को हटा सकता है , लेनदेन कर सकता है और प्रिंटर से एक खाली पृष्ठ थूक सकता है ... लेकिन पाइथन मैनुअल में वर्णित यह क्या करना चाहिए इसकी एक सामान्य समझ है।

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

एक सार बेस क्लास (एबीसी) परिभाषित करना कक्षा कार्यान्वयनकर्ताओं और कॉलर्स के बीच अनुबंध बनाने का एक तरीका है। यह सिर्फ विधि नामों की एक सूची नहीं है, लेकिन उन तरीकों को साझा करने के बारे में एक साझा समझ है। यदि आप इस एबीसी से प्राप्त होते हैं, तो आप print() विधि के अर्थशास्त्र सहित टिप्पणियों में वर्णित सभी नियमों का पालन करने का वादा कर रहे हैं।

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

पायथन में बतख टाइपिंग के पुराने तरीकों से इस्तेमाल होने के नाते, मैं एबीसी (सार आधार वर्ग) की आवश्यकता को समझने में असफल रहा। उनकी help करने के तरीके पर help अच्छी है।

मैंने PEP में तर्क पढ़ने की कोशिश की, लेकिन यह मेरे सिर पर चला गया। अगर मैं एक परिवर्तनीय अनुक्रम कंटेनर की तलाश में था, तो मैं __setitem__ जांच करता __setitem__ , या अधिक उपयोग करने की कोशिश की जाती है ( EAFP )। मैं numbers मॉड्यूल के लिए वास्तविक जीवन उपयोग में नहीं आया हूं, जो एबीसी का उपयोग करता है, लेकिन यह मुझे सबसे नज़दीक समझना है।

क्या कोई मुझे तर्क बता सकता है, कृपया?


@ ओडथिंकिंग का जवाब गलत नहीं है, लेकिन मुझे लगता है कि यह वास्तविक , व्यावहारिक कारण से चूक जाता है पाइथन के पास बतख-टाइपिंग की दुनिया में एबीसी है।

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

पायथन का स्रोत कोड अनुकरणीय है। Here है कि कैसे collections.Container नियंत्रक मानक पुस्तकालय (लेखन के समय) में परिभाषित किया गया है:

class Container(metaclass=ABCMeta):
    __slots__ = ()

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if any("__contains__" in B.__dict__ for B in C.__mro__):
                return True
        return NotImplemented

__subclasshook__ की यह परिभाषा कहती है कि __contains__ विशेषता वाले किसी भी वर्ग को कंटेनर का उप-वर्ग माना जाता है, भले ही यह सीधे इसे उपclass न करे। तो मैं इसे लिख सकता हूं:

class ContainAllTheThings(object):
    def __contains__(self, item):
        return True

>>> issubclass(ContainAllTheThings, collections.Container)
True
>>> isinstance(ContainAllTheThings(), collections.Container)
True

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

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

मैं कभी-कभी खुद को पॉलीमोर्फिक फ़ंक्शंस लिखता हूं जो एक आइटम या वस्तुओं के संग्रह पर कार्य कर सकता है, और मुझे hasattr(x, '__iter__') या समकक्ष try...except से अधिक पढ़ने योग्य होने के लिए isinstance(x, collections.Iterable) hasattr(x, '__iter__') जाता है try...except ब्लॉक के अलावा। (यदि आपको पायथन नहीं पता था, तो उनमें से कौन सा कोड स्पष्ट करने का इरादा रखेगा?)

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

* बहस में शामिल होने के बिना जावा जावा "पारंपरिक" ओओ सिस्टम है या नहीं ...

अनुपूरक : भले ही एक सार आधार वर्ग isinstance और issubclass करने के व्यवहार को ओवरराइड कर सकता है, फिर भी यह issubclass के MRO में प्रवेश नहीं करता है। यह ग्राहकों के लिए एक संभावित गड़बड़ी है: प्रत्येक वस्तु जिसके लिए isinstance(x, MyABC) == True है MyABC पर परिभाषित MyABC

class MyABC(metaclass=abc.ABCMeta):
    def abc_method(self):
        pass
    @classmethod
    def __subclasshook__(cls, C):
        return True

class C(object):
    pass

# typical client code
c = C()
if isinstance(c, MyABC):  # will be true
    c.abc_method()  # raises AttributeError

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


यह निर्धारित करेगा कि कोई ऑब्जेक्ट प्रोटोकॉल में सभी विधियों की उपस्थिति के बिना किसी भी प्रोटोकॉल का समर्थन करता है या बिना किसी समर्थन के "दुश्मन" क्षेत्र में गहरे अपवाद को ट्रिगर किए बिना किसी दिए गए प्रोटोकॉल का समर्थन करता है।





abc