@ ओडिन्थंकिंग का उत्तर गलत नहीं है, लेकिन मुझे लगता है कि यह वास्तविक , व्यावहारिक कारण याद करता है , अजगर टाइपिंग की दुनिया में एबीसी है।
सार विधियां साफ-सुथरी हैं, लेकिन मेरी राय में वे वास्तव में डक टाइपिंग द्वारा कवर किए गए किसी भी उपयोग के मामलों को नहीं भरती हैं। सार आधार वर्ग 'में वास्तविक शक्ति निहित है जिस तरह से वे आप के व्यवहार को अनुकूलित करने के लिए अनुमति देते हैं isinstance
औरissubclass
। ( __subclasshook__
मूल रूप से पायथन __instancecheck__
और__subclasscheck__
हुक के शीर्ष पर एक फ्रेंडली एपीआई है ।) कस्टम प्रकारों पर काम करने के लिए निर्मित निर्माणों को अपनाना पायथन के दर्शन का बहुत हिस्सा है।
पायथन का स्रोत कोड अनुकरणीय है। यहाँ बताया 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 ContainAllTheThings(object):
def __contains__(self, item):
return True
>>> issubclass(ContainAllTheThings, collections.Container)
True
>>> isinstance(ContainAllTheThings(), collections.Container)
True
दूसरे शब्दों में, यदि आप सही इंटरफ़ेस लागू करते हैं तो आप एक उपवर्ग हैं! एबीसी, पाइकॉन में इंटरफेस को परिभाषित करने का एक औपचारिक तरीका प्रदान करते हैं, जबकि बतख-टाइपिंग की भावना के लिए सही रहते हैं। इसके अलावा, यह एक तरह से काम करता है जो ओपन-क्लोज्ड सिद्धांत का सम्मान करता है ।
पायथन का ऑब्जेक्ट मॉडल सतही रूप से "अधिक" पारंपरिक "OO प्रणाली (जिससे मैं जावा * का अर्थ है) के समान दिखता हूं - हमें yer कक्षाएं, yer ऑब्जेक्ट्स, yer तरीके मिले - लेकिन जब आप सतह को खरोंच करते हैं तो आपको कुछ और समृद्ध और मिलेंगे।" अधिक लचीला। इसी तरह, पायथन की अमूर्त आधार कक्षाओं की धारणा एक जावा डेवलपर के लिए पहचानी जा सकती है, लेकिन व्यवहार में वे एक बहुत ही अलग उद्देश्य के लिए अभिप्रेत हैं।
मैं कभी-कभी खुद को बहुरूपतापूर्ण कार्य लिखने के लिए पाता हूं जो किसी एक आइटम या वस्तुओं के संग्रह पर कार्य कर सकता है, और मुझे लगता है isinstance(x, collections.Iterable)
hasattr(x, '__iter__')
एक समान try...except
ब्लॉक की तुलना में बहुत अधिक पठनीय लगता है । (यदि आप पायथन को नहीं जानते हैं, तो उन तीनों में से कौन सा कोड का इरादा स्पष्ट करेगा?)
उस ने कहा, मुझे लगता है कि मुझे शायद ही कभी अपनी एबीसी लिखने की जरूरत है और मैं आमतौर पर रिफैक्टिंग के माध्यम से एक की आवश्यकता की खोज करता हूं। अगर मैं एक बहुरूपिक फ़ंक्शन को बहुत अधिक विशेषता जांच करता हुआ देखता हूं, या बहुत सारे कार्य एक ही विशेषता जांच करता है, तो गंध एक एबीसी के अस्तित्व को निकालने का इंतजार करने का सुझाव देता है।
* इस बात पर बहस किए बिना कि क्या जावा एक "पारंपरिक" OO प्रणाली है ...
परिशिष्ट : भले ही एक सार आधार वर्ग के व्यवहार को ओवरराइड कर सकता है isinstance
और issubclass
, यह अभी भी वर्चुअल उपवर्ग के MRO में प्रवेश नहीं करता है । यह ग्राहकों के लिए एक संभावित नुकसान है: प्रत्येक वस्तु जिसके isinstance(x, MyABC) == True
लिए विधियों को परिभाषित नहीं किया गया है 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__
अपने एबीसी परिभाषित अमूर्त तरीकों के सेट के अनुरूप अपनी परिभाषा बनानी चाहिए ।
__contains__
और एक वर्ग जो विरासत में मिला हैcollections.Container
? आपके उदाहरण में, पायथन में हमेशा एक साझा समझ थी__str__
। लागू करना__str__
कुछ एबीसी से विरासत के रूप में एक ही वादे करता है और फिर लागू करना__str__
। दोनों मामलों में आप अनुबंध को तोड़ सकते हैं; स्थैतिक टाइपिंग में हमारे पास कोई सिद्ध शब्द नहीं है।