@ অডথিংকিংয়ের উত্তরটি ভুল নয়, তবে আমি মনে করি এটি পাইথনের হাঁস-টাইপিংয়ের জগতে এবিসি থাকার বাস্তব , ব্যবহারিক কারণটি মিস করেছে।
বিমূর্ত পদ্ধতিগুলি ঝরঝরে, তবে আমার মতে তারা ইতিমধ্যে হাঁসের টাইপিংয়ের দ্বারা আচ্ছাদিত কোনও ব্যবহারের কেস পূরণ করে না। সারাংশ বেস ক্লাস 'থেকে প্রকৃত শক্তি মিথ্যা পথ তারা তোমার আচরণ কাস্টমাইজ করার অনুমতি 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
অন্য কথায়, আপনি যদি সঠিক ইন্টারফেস প্রয়োগ করেন তবে আপনি একটি সাবক্লাস! হাঁস-টাইপিংয়ের মনোভাবের প্রতি সত্য হয়ে ওঠার সাথে সাথে এবিসি পাইথনে ইন্টারফেসগুলি সংজ্ঞায়িত করার আনুষ্ঠানিক উপায় সরবরাহ করে। তদ্ব্যতীত, এটি এমনভাবে কাজ করে যা ওপেন-বদ্ধ নীতিটিকে সম্মান করে ।
পাইথনের অবজেক্টের মডেল দেখতে আরও বেশি "traditionalতিহ্যবাহী" ওও সিস্টেমের (যেমনটি আমি জাভা *) এর সাথে অনুরূপ দেখতে পেয়েছি - আমরা ইয়ার ক্লাস, ইয়ার অবজেক্টস, ইয়ার পদ্ধতিগুলি পেয়েছি - তবে আপনি যখন পৃষ্ঠটি স্ক্র্যাচ করবেন তখন আপনি আরও সমৃদ্ধ কিছু খুঁজে পাবেন এবং আরো নমনীয়. তেমনি, অ্যাজস্ট্রাক্ট বেস ক্লাসগুলির পাইথনের ধারণাটি কোনও জাভা বিকাশকারীকে স্বীকৃত হতে পারে, তবে বাস্তবে তারা একে অন্যরকম উদ্দেশ্যে উদ্দিষ্ট।
আমি মাঝে মাঝে নিজেকে পলিমারফিক ফাংশনগুলি লিখতে দেখি যা একক আইটেম বা আইটেমের সংকলনে কাজ isinstance(x, collections.Iterable)করতে পারে এবং আমি তার চেয়ে অনেক বেশি পঠনযোগ্য hasattr(x, '__iter__')বা সমতুল্য try...exceptব্লক বলে মনে করি। (যদি আপনি পাইথন না জানতেন তবে এই তিনজনের মধ্যে কোনটি কোডটির উদ্দেশ্যটি পরিষ্কার করে দেবে?)
এটি বলেছিল, আমি দেখতে পেয়েছি যে আমার নিজের কদাচিৎ আমার নিজের এবিসি লিখতে হবে এবং আমি সাধারণত রিফ্যাক্টরিংয়ের মাধ্যমে একটিটির প্রয়োজনীয়তা আবিষ্কার করি। যদি আমি দেখতে পাই যে বহুগুণিত ক্রিয়াকলাপটি অনেকগুলি অ্যাট্রিবিউট চেক তৈরি করে, বা একই বৈশিষ্ট্যযুক্ত চেক তৈরি করে প্রচুর ফাংশন, তবে এই গন্ধটি উত্তোলনের জন্য অপেক্ষা করা একটি এবিসির অস্তিত্বের পরামর্শ দেয়।
* জাভা একটি "traditionalতিহ্যবাহী" ওও সিস্টেম কিনা তা নিয়ে বিতর্কে না গিয়ে ...
সংযোজন : এমনকি যদিও একটি বিমূর্ত বেস ক্লাসের আচরণ পাল্টাতে পারেন isinstanceএবং issubclass, এটা এখনও প্রবেশ করে না ম্রো ভার্চুয়াল উপশ্রেণী করুন। এটি ক্লায়েন্টদের জন্য একটি সম্ভাব্য সমস্যা: প্রতিটি বস্তুর জন্য নয় যার জন্য 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__। উভয় ক্ষেত্রেই আপনি চুক্তিটি ভঙ্গ করতে পারেন; স্ট্যাটিক টাইপিংয়ের মতো কোনও প্রমাণযোগ্য শব্দার্থবিজ্ঞান নেই।