abc --- کلاسهای پایه انتزاعی¶
کد منبع: Lib/abc.py
این ماژول زیرساخت لازم برای تعریف کلاسهای پایه انتزاعی (ABCها) در پایتون را فراهم میکند، همانطور که در PEP 3119 شرح داده شده است؛ برای آگاهی از دلیل افزودن این قابلیت به پایتون، این PEP را ببینید. (همچنین PEP 3141 و ماژول numbers را در مورد سلسلهمراتب نوع برای اعداد بر پایه ABCها ببینید.)
ماژول collections تعدادی کلاس ملموس دارد که از ABCها مشتق شدهاند؛ البته میتوان اینها را نیز بیشتر مشتق کرد. علاوه بر این، زیرماژول collections.abc تعدادی ABC دارد که میتوان از آنها برای بررسی اینکه آیا یک کلاس یا نمونه، رابط خاصی را فراهم میکند، استفاده کرد؛ برای مثال، اگر hashable باشد یا یک mapping باشد.
این ماژول، فراکلاس ABCMeta را برای تعریف ABCها و کلاس کمکی ABC را فراهم میکند تا بهعنوان جایگزین، بتوانید ABCها را از طریق ارثبری تعریف کنید:
- class abc.ABC¶
یک کلاس کمکی که
ABCMetaرا بهعنوان فراکلاس خود دارد. با این کلاس، میتوان یک کلاس پایه انتزاعی را صرفاً با مشتق شدن ازABCایجاد کرد و از کاربرد گاه گیجکنندهی فراکلاس اجتناب نمود، برای مثال:from abc import ABC class MyABC(ABC): pass
توجه داشته باشید که نوع
ABCهمچنانABCMetaاست؛ بنابراین ارثبری ازABCنیازمند رعایت نکات احتیاطی معمول در مورد استفاده از فراکلاس است، زیرا ارثبری چندگانه ممکن است به تعارضهای فراکلاس منجر شود. همچنین میتوان یک کلاس پایه انتزاعی را با ارسال کلیدواژه metaclass و استفاده مستقیم ازABCMetaتعریف کرد، برای مثال:from abc import ABCMeta class MyABC(metaclass=ABCMeta): pass
اضافه شده در نسخهی 3.4.
- class abc.ABCMeta¶
فراکلاس برای تعریف کلاسهای پایه انتزاعی (ABCها).
از این فراکلاس برای ایجاد یک ABC استفاده کنید. یک ABC بهطور مستقیم قابل زیرکلاسبندی است و سپس بهعنوان یک کلاس میکساین عمل میکند. همچنین میتوانید کلاسهای عینی غیرمرتبط (حتی کلاسهای توکار) و ABCهای غیرمرتبط را بهعنوان «زیرکلاسهای مجازی» ثبت کنید — این کلاسها و زیرکلاسهای مشتقشده از آنها از دید تابع توکار
issubclass()زیرکلاسهای ABC ثبتکننده محسوب خواهند شد، اما ABC ثبتکننده در MRO (ترتیب حل متد) آنها ظاهر نخواهد شد و پیادهسازیهای متد تعریفشده توسط ABC ثبتکننده فراخوانیپذیر نخواهند بود (حتی از طریقsuper()نیز). [1]کلاسهایی که با فراکلاس
ABCMetaایجاد شدهاند، متد زیر را دارند:- register(subclass)¶
subclass را بهعنوان یک «زیرکلاس مجازی» از این ABC ثبت کنید. برای مثال:
from abc import ABC class MyABC(ABC): pass MyABC.register(tuple) assert issubclass(tuple, MyABC) assert isinstance((), MyABC)
تغییر یافته در نسخهی 3.3: زیرکلاس ثبتشده را برمیگرداند تا امکان استفاده بهعنوان دکوراتور کلاس فراهم شود.
تغییر یافته در نسخهی 3.4: برای تشخیص فراخوانیهای
register()، میتوانید از تابعget_cache_token()استفاده کنید.
همچنین میتوانید این متد را در یک کلاس پایه انتزاعی بازنویسی کنید:
- __subclasshook__(subclass)¶
(باید بهعنوان متد کلاس تعریف شود.)
بررسی میکند که آیا subclass زیرکلاسی از این ABC در نظر گرفته میشود یا خیر. این بدان معناست که شما میتوانید رفتار
issubclass()را بیشتر سفارشیسازی کنید، بدون نیاز به فراخوانیregister()برای هر کلاسی که میخواهید آن را زیرکلاسی از ABC در نظر بگیرید. (این متد کلاس از متد__subclasscheck__()در ABC فراخوانی میشود.)این متد باید
True،FalseیاNotImplementedرا برگرداند. اگرTrueرا برگرداند، زیرکلاس بهعنوان زیرکلاسی از این ABC در نظر گرفته میشود. اگرFalseرا برگرداند، زیرکلاس بهعنوان زیرکلاسی از این ABC در نظر گرفته نمیشود، حتی اگر در حالت عادی یک زیرکلاس باشد. اگرNotImplementedرا برگرداند، بررسی زیرکلاس با سازوکار معمول ادامه مییابد.
برای نمایش این مفاهیم، این نمونه تعریف ABC را ببینید:
class Foo: def __getitem__(self, index): ... def __len__(self): ... def get_iterator(self): return iter(self) class MyIterable(ABC): @abstractmethod def __iter__(self): while False: yield None def get_iterator(self): return self.__iter__() @classmethod def __subclasshook__(cls, C): if cls is MyIterable: if any("__iter__" in B.__dict__ for B in C.__mro__): return True return NotImplemented MyIterable.register(Foo)
کلاس پایه انتزاعی (ABC)
MyIterableمتد استاندارد پیمایشپذیر،__iter__()، را بهعنوان یک متد انتزاعی تعریف میکند. پیادهسازی ارائهشده در اینجا همچنان میتواند از زیرکلاسها فراخوانی شود. متدget_iterator()نیز بخشی از کلاس پایه انتزاعیMyIterableاست، اما نیازی به بازنویسی آن در کلاسهای مشتقشده غیرانتزاعی نیست.متد کلاسی
__subclasshook__()تعریفشده در اینجا بیان میکند که هر کلاسی که یک متد__iter__()در__dict__خود (یا در دیکشنری یکی از کلاسهای پایهی خود، که از طریق فهرست__mro__به آنها دسترسی پیدا میشود) داشته باشد، بهعنوان یکMyIterableنیز در نظر گرفته میشود.سرانجام، آخرین خط
Fooرا به یک زیرکلاس مجازی ازMyIterableتبدیل میکند، اگرچه متد__iter__()را تعریف نمیکند (از پروتکل پیمایشپذیر بهسبک قدیمی استفاده میکند که بر حسب__len__()و__getitem__()تعریف شده است). توجه داشته باشید که این کارget_iteratorرا بهعنوان متدی ازFooدر دسترس قرار نمیدهد، بنابراین بهصورت جداگانه ارائه شده است.
ماژول abc همچنین دکوراتور زیر را نیز فراهم میکند:
- @abc.abstractmethod¶
دکوراتوری که متدهای انتزاعی را نشان میدهد.
استفاده از این دکوراتور مستلزم آن است که فراکلاسِ کلاس
ABCMetaباشد یا از آن مشتق شده باشد. کلاسی که فراکلاس آن ازABCMetaمشتق شده باشد، نمیتواند نمونهسازی شود، مگر آنکه تمام متدها و ویژگیهای انتزاعی آن بازنویسی شده باشند. میتوان متدهای انتزاعی را با استفاده از هر یک از سازوکارهای معمول فراخوانی 'super' فراخوانی کرد. میتوان از@abstractmethodبرای اعلام متدهای انتزاعی برای ویژگیها و توصیفگرها استفاده کرد.افزودن متدهای انتزاعی بهصورت پویا به یک کلاس، یا تلاش برای تغییر وضعیت انتزاعی یک متد یا کلاس پس از ایجاد آن، تنها با استفاده از تابع
update_abstractmethods()پشتیبانی میشود.@abstractmethodتنها بر زیرکلاسهای مشتقشده با وراثت معمولی تأثیر میگذارد؛ «زیرکلاسهای مجازی» ثبتشده با متدregister()مربوط به ABC تحت تأثیر قرار نمیگیرند.هنگامی که
@abstractmethodدر ترکیب با سایر توصیفگرهای متد اعمال میشود، باید بهعنوان درونیترین دکوراتور اعمال شود، همانطور که در مثالهای استفاده زیر نشان داده شده است:class C(ABC): @abstractmethod def my_abstract_method(self, arg1): ... @classmethod @abstractmethod def my_abstract_classmethod(cls, arg2): ... @staticmethod @abstractmethod def my_abstract_staticmethod(arg3): ... @property @abstractmethod def my_abstract_property(self): ... @my_abstract_property.setter @abstractmethod def my_abstract_property(self, val): ... @abstractmethod def _get_x(self): ... @abstractmethod def _set_x(self, val): ... x = property(_get_x, _set_x)
برای تعامل صحیح با سازوکار کلاس پایه انتزاعی، توصیفگر باید خود را با استفاده از
__isabstractmethod__بهعنوان انتزاعی معرفی کند. بهطور کلی، اگر هر یک از متدهای استفادهشده برای تشکیل توصیفگر انتزاعی باشند، این ویژگی بایدTrueباشد. برای مثال،@propertyتوکار پایتون معادل زیر را انجام میدهد:class Descriptor: ... @property def __isabstractmethod__(self): return any(getattr(f, '__isabstractmethod__', False) for f in (self._fget, self._fset, self._fdel))
توجه
برخلاف متدهای انتزاعی جاوا، این متدهای انتزاعی ممکن است پیادهسازی داشته باشند. این پیادهسازی را میتوان از طریق سازوکار
super()از کلاسی که آن را بازنویسی میکند فراخوانی کرد. این میتواند بهعنوان پایانهای برای فراخوانی super در چارچوبی که از وراثت چندگانهی مشارکتی استفاده میکند، مفید باشد.
ماژول abc همچنین از دکوراتورهای قدیمی زیر پشتیبانی میکند:
- @abc.abstractclassmethod¶
اضافه شده در نسخهی 3.2.
منسوخ شده از نسخهی 3.3: اکنون میتوان از
@classmethodهمراه با@abstractmethodاستفاده کرد، که این دکوراتور را زائد میسازد.زیرکلاسی از
classmethodتوکار، که نشاندهندهی یک classmethod انتزاعی است. در سایر موارد، مشابه@abstractmethodاست.این حالت خاص منسوخ شده است، زیرا دکوراتور
@classmethodاکنون هنگامی که به یک متد انتزاعی اعمال شود، بهدرستی بهعنوان انتزاعی شناسایی میشود:class C(ABC): @classmethod @abstractmethod def my_abstract_classmethod(cls, arg): ...
- @abc.abstractstaticmethod¶
اضافه شده در نسخهی 3.2.
منسوخ شده از نسخهی 3.3: اکنون میتوانید از
@staticmethodهمراه با@abstractmethodاستفاده کنید، که این دکوراتور را زائد میکند.زیرکلاسی از
staticmethodتوکار که نشاندهنده یک staticmethod انتزاعی است. در غیر این صورت، مشابه@abstractmethodاست.این حالت خاص منسوخ شده است، زیرا دکوراتور
@staticmethodاکنون هنگامی که به یک متد انتزاعی اعمال شود، بهدرستی بهعنوان انتزاعی شناسایی میشود:class C(ABC): @staticmethod @abstractmethod def my_abstract_staticmethod(arg): ...
- @abc.abstractproperty¶
منسوخ شده از نسخهی 3.3: اکنون میتوان از
@property،@property.getter،@property.setterو@property.deleterبههمراه@abstractmethodاستفاده کرد، که این دکوراتور را زائد میکند.زیرکلاسی از
propertyتوکار، که نشاندهندهی یک ویژگی انتزاعی است.این حالت خاص منسوخ شده است، زیرا دکوراتور
@propertyاکنون هنگام اعمال بر یک متد انتزاعی بهدرستی بهعنوان انتزاعی شناسایی میشود:class C(ABC): @property @abstractmethod def my_abstract_property(self): ...
مثال بالا یک ویژگی فقطخواندنی تعریف میکند؛ شما همچنین میتوانید با علامتگذاری مناسب یک یا چند مورد از متدهای زیربنایی بهعنوان انتزاعی، یک ویژگی انتزاعی با قابلیت خواندن و نوشتن تعریف کنید:
class C(ABC): @property def x(self): ... @x.setter @abstractmethod def x(self, val): ...
اگر تنها برخی از کامپوننتها انتزاعی باشند، تنها همان کامپوننتها باید بهروزرسانی شوند تا یک پراپرتی عینی در یک زیرکلاس ایجاد شود:
class D(C): @C.x.setter def x(self, val): ...
ماژول abc همچنین توابع زیر را فراهم میکند:
- abc.get_cache_token()¶
توکن فعلی نهانگاه کلاس پایه انتزاعی را بازمیگرداند.
توکن یک شیء غیرشفاف است (که از آزمون برابری پشتیبانی میکند) و نسخه کنونی نهانگاه کلاس پایه انتزاعی برای زیرکلاسهای مجازی را شناسایی میکند. توکن با هر فراخوانی
ABCMeta.register()روی هر ABC تغییر میکند.اضافه شده در نسخهی 3.4.
- abc.update_abstractmethods(cls)¶
تابعی برای محاسبهی مجدد وضعیت انتزاعی بودن یک کلاس انتزاعی. اگر متدهای انتزاعی یک کلاس پس از ایجاد آن پیادهسازی یا تغییر کرده باشند، باید این تابع فراخوانی شود. معمولاً این تابع باید از درون یک دکوراتور کلاس فراخوانی شود.
cls را برمیگرداند تا امکان استفاده بهعنوان دکوراتور کلاس فراهم شود.
اگر cls نمونهای از
ABCMetaنباشد، هیچ کاری انجام نمیدهد.توجه
این تابع فرض میکند که ابرکلاسهای cls از قبل بهروزرسانی شدهاند. این تابع هیچ زیرکلاسی را بهروزرسانی نمیکند.
اضافه شده در نسخهی 3.10.
پانویسها