पायथन में अमूर्त वर्ग और इंटरफ़ेस के बीच अंतर


जवाबों:


618

आप कभी-कभी जो देखेंगे वह निम्नलिखित है:

class Abstract1( object ):
    """Some description that tells you it's abstract,
    often listing the methods you're expected to supply."""
    def aMethod( self ):
        raise NotImplementedError( "Should have implemented this" )

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

और सार और इंटरफ़ेस के बीच का अंतर एक हेयरस्प्लिंग बात है जब आपने डकार टाइपिंग की है।

जावा इंटरफेस का उपयोग करता है क्योंकि इसमें एकाधिक उत्तराधिकार नहीं है।

क्योंकि पायथन में कई विरासतें हैं, इसलिए आप कुछ इस तरह भी देख सकते हैं

class SomeAbstraction( object ):
    pass # lots of stuff - but missing something

class Mixin1( object ):
    def something( self ):
        pass # one implementation

class Mixin2( object ):
    def something( self ):
        pass # another

class Concrete1( SomeAbstraction, Mixin1 ):
    pass

class Concrete2( SomeAbstraction, Mixin2 ):
    pass

यह कंक्रीट उपवर्ग बनाने के लिए मिश्रणों के साथ एक प्रकार के अमूर्त सुपरक्लास का उपयोग करता है जो कि घृणास्पद हैं।


5
एस। लोट, क्या आपका मतलब है कि बतख के कारण है-ए (इंटरफ़ेस) और अंतर-ए (वंशानुक्रम) के बीच का अंतर पर्याप्त नहीं है?
लोरेंजो

3
अमूर्त और इंटरफ़ेस के बीच अंतर एक हेयरस्प्लिंग बात है जब आपने डकार टाइपिंग की है। मुझे नहीं पता कि "पर्याप्त" का क्या मतलब है। यह "वास्तविक" है - इसमें पदार्थ है - एक डिजाइन के दृष्टिकोण से। लेकिन भाषा के नजरिए से कोई समर्थन नहीं हो सकता है। आप एक अमूर्त वर्ग और पायथन में एक इंटरफ़ेस वर्ग परिभाषा के बीच अंतर करने के लिए सम्मेलनों को अपना सकते हैं।
S.Lott

26
@ L.DeLeo - क्या आपको यकीन है कि आपकी धारणा एक-एक बनाम सही है? मैं आम तौर पर अंतर को देखता हूं जैसे कि एक = सदस्य चर बनाम है-एक = वंशानुक्रम (मूल वर्ग या इंटरफ़ेस)। जावा में तुलना या सूची सोचो; वे एक रिश्ते हैं, चाहे वे इंटरफेस या अमूर्त वर्ग हों।
dimo414

43
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))अधिक जानकारीपूर्ण त्रुटि संदेश है :)
naught101

9
@ लोरेंजो के पास एक संबंध है जिसका वंशानुक्रम, बत्तख टाइपिंग, इंटरफेस और अमूर्त वर्गों से कोई लेना-देना नहीं है (चारों एक संबंध है)।
कार्ल रिक्टर

196

पायथन में अमूर्त वर्ग और इंटरफ़ेस के बीच अंतर क्या है?

ऑब्जेक्ट के लिए एक इंटरफ़ेस, उस ऑब्जेक्ट पर विधियों और विशेषताओं का एक सेट है।

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

एब्सट्रैक्ट बेस क्लास का उपयोग करना

उदाहरण के लिए, मान लें कि हम collectionsमॉड्यूल से अमूर्त आधार वर्गों में से एक का उपयोग करना चाहते हैं :

import collections
class MySet(collections.Set):
    pass

यदि हम इसका उपयोग करने का प्रयास करते हैं, तो हमें एक TypeErrorकारण मिलता है क्योंकि हमने जो वर्ग बनाया है वह सेट के अपेक्षित व्यवहार का समर्थन नहीं करता है:

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

इसलिए हम पर लागू करने के लिए आवश्यक हैं कम से कम __contains__ , __iter__और __len__। आइए प्रलेखन से इस कार्यान्वयन उदाहरण का उपयोग करें :

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

कार्यान्वयन: एक सार बेस क्लास बनाना

हम प्रासंगिक तरीकों पर डेकोरेटर abc.ABCMetaका उपयोग करके और मेटाक्लर की स्थापना करके अपना स्वयं का सार बेस क्लास बना सकते हैं abc.abstractmethod। मेटाक्लास को सजाए गए कार्यों को __abstractmethods__विशेषता में जोड़ा जाएगा , जब तक कि वे परिभाषित न हों, तब तक रोकना संभव है।

import abc

उदाहरण के लिए, "अपूरणीय" को किसी ऐसी चीज के रूप में परिभाषित किया जाता है जिसे शब्दों में व्यक्त किया जा सकता है। मान लें कि हम एक सार आधार वर्ग को परिभाषित करना चाहते हैं, जो कि पवित्र है, पायथन 2 में:

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

या पायथन 3 में, मेटाक्लास घोषणा में थोड़े बदलाव के साथ:

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

अब यदि हम इंटरफ़ेस को लागू किए बिना एक पवित्र वस्तु बनाने की कोशिश करते हैं:

class MyEffable(Effable): 
    pass

और इसे तत्काल करने का प्रयास:

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

हमें बताया गया है कि हमने काम पूरा नहीं किया है।

अब यदि हम अपेक्षित इंटरफ़ेस प्रदान करते हैं:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

हम तब सार से प्राप्त वर्ग के ठोस संस्करण का उपयोग करने में सक्षम हैं:

>>> me = MyEffable()
>>> print(me)
expressable!

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

निष्कर्ष

हमने प्रदर्शित किया है कि एक मूल बेस क्लास का निर्माण पायथन में कस्टम ऑब्जेक्ट्स के लिए इंटरफेस को परिभाषित करता है।


101

पायथन> = 2.6 में सार बेस कक्षाएं हैं

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

वहाँ भी है Zope इंटरफेस मॉड्यूल है, जो मुड़ की तरह, zope के बाहर परियोजनाओं द्वारा प्रयोग किया जाता है। मैं वास्तव में इससे परिचित नहीं हूं, लेकिन यहां एक विकी पेज है जो मदद कर सकता है।

सामान्य तौर पर, आपको एब्स्ट्रैक्ट क्लासेस की अवधारणा की आवश्यकता नहीं है, या अजगर में इंटरफेस (संपादित करें - विवरणों के लिए S.Lott का उत्तर देखें)।


2
अजगर में एबीसी का उपयोग करके आप क्या हासिल करते हैं?
CpILL

38

पायथन वास्तव में या तो अवधारणा नहीं है।

यह बतख टाइपिंग का उपयोग करता है, जिसने इंटरफेस की आवश्यकता को हटा दिया (कम से कम कंप्यूटर के लिए :-))

पायथन <= 2.5: बेस कक्षाएं स्पष्ट रूप से मौजूद हैं, लेकिन एक विधि को 'शुद्ध आभासी' के रूप में चिह्नित करने का कोई स्पष्ट तरीका नहीं है, इसलिए वर्ग वास्तव में सार नहीं है।

पायथन> = 2.6: सार आधार कक्षाएं मौजूद हैं ( http://docs.python.org/library/abc.html )। और आपको उन विधियों को निर्दिष्ट करने की अनुमति देता है जिन्हें उपवर्गों में लागू किया जाना चाहिए। मुझे सिंटैक्स पसंद नहीं है, लेकिन सुविधा है। अधिकांश समय यह संभव है कि 'ग्राहक' का उपयोग करके डक टाइपिंग का उपयोग करना बेहतर हो।


3
पायथन 3.0 वास्तविक अमूर्त आधार वर्गों को जोड़ता है। उनका उपयोग संग्रह मॉड्यूल के साथ-साथ अन्य स्थानों पर भी किया जाता है। docs.python.org/3.0/library/abc.html
लारा

क्यों बतख टाइपिंग के संदर्भ में इंटरफेस की आवश्यकता को दूर करने में मदद मिलेगी। यह मेरे लिए स्पष्ट नहीं लगता है कि डक टाइपिंग, जिसे मैं किसी भी विधि पर किसी भी विधि या विशेषता को "प्रहार" करने की क्षमता के रूप में समझता हूं, इसका मतलब यह होगा कि आपको आवश्यक व्यवहार निर्दिष्ट करने की आवश्यकता नहीं है (और आपको याद दिलाने के लिए कंपाइलर प्राप्त करना होगा। उन्हें लागू करने के लिए), जो है कि मैं सार बेस कक्षाएं कैसे समझता हूं।
रेब.कबिन

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

35

समझाने के लिए और अधिक बुनियादी तरीके से: एक इंटरफ़ेस एक खाली मफिन पैन की तरह है। यह एक वर्ग फ़ाइल है जिसमें ऐसी पद्धति परिभाषाएँ हैं जिनका कोई कोड नहीं है।

एक सार वर्ग एक ही बात है, लेकिन सभी कार्यों को खाली करने की आवश्यकता नहीं है। कुछ में कोड हो सकते हैं। यह सख्ती से खाली नहीं है।

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


इस अंतर के लिए +1 जहां एबीसी का स्वयं का कार्यान्वयन हो सकता है - जो अपने आप को बाहर करने का एक बहुत अच्छा तरीका लगता है
टिटौ

17

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

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

http://docs.python.org/library/abc.html


2

अमूर्त कक्षाएं वे कक्षाएं होती हैं जिनमें एक या एक से अधिक सार विधियां होती हैं। अमूर्त विधियों के साथ, सार वर्गों में स्थिर, वर्ग और उदाहरण विधियां हो सकती हैं। लेकिन इंटरफ़ेस के मामले में, इसमें केवल अमूर्त विधियाँ होंगी अन्य नहीं। इसलिए यह अमूर्त वर्ग को विरासत में लेने के लिए अनिवार्य नहीं है, लेकिन इनहेरिट इंटरफ़ेस के लिए अनिवार्य है।


1

पूर्णता के लिए, हमें PEP3119 का उल्लेख करना चाहिए जहां एबीसी को इंटरफेस के साथ पेश किया गया था और मूल तालिन की टिप्पणी के साथ तुलना की गई थी ।

सार वर्ग सही इंटरफ़ेस नहीं है:

  • वंशानुक्रम पदानुक्रम के अंतर्गत आता है
  • पारस्परिक है

लेकिन अगर आप इसे अपने तरीके से लिखने पर विचार करते हैं:

def some_function(self):
     raise NotImplementedError()

interface = type(
    'your_interface', (object,),
    {'extra_func': some_function,
     '__slots__': ['extra_func', ...]
     ...
     '__instancecheck__': your_instance_checker,
     '__subclasscheck__': your_subclass_checker
     ...
    }
)

ok, rather as a class
or as a metaclass
and fighting with python to achieve the immutable object
and doing refactoring
...

आप काफी तेजी से महसूस करेंगे कि आप अंततः प्राप्त करने के लिए पहिया का आविष्कार कर रहे हैं abc.ABCMeta

abc.ABCMeta लापता इंटरफ़ेस कार्यक्षमता के एक उपयोगी जोड़ के रूप में प्रस्तावित किया गया था, और यह अजगर की तरह एक भाषा में पर्याप्त उचित है।

निश्चित रूप से, यह संस्करण 3 को लिखते समय और नए सिंटैक्स और अपरिवर्तनीय इंटरफ़ेस अवधारणा को जोड़ते हुए बेहतर तरीके से बढ़ाया जा सकता था ...

निष्कर्ष:

The abc.ABCMeta IS "pythonic" interface in python
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.