“Python/docs/3.9/library/abc”的版本间差异
(autoload) |
小 (Page commit) |
||
第1行: | 第1行: | ||
+ | {{DISPLAYTITLE:abc — 抽象基类 — Python 文档}} | ||
<div id="module-abc" class="section"> | <div id="module-abc" class="section"> | ||
<span id="abc-abstract-base-classes"></span> | <span id="abc-abstract-base-classes"></span> | ||
− | = | + | = abc — 抽象基类 = |
− | ''' | + | '''源代码:''' [[#id1|<span id="id2" class="problematic">:source:`Lib/abc.py`</span>]] |
− | |||
− | |||
− | |||
− | |||
− | + | ----- | |
− | |||
− | |||
− | |||
− | |||
− | + | 该模块提供了在 Python 中定义 [[../../glossary#term-abstract-base-class|抽象基类]] (ABC) 的基础结构,如 <span id="index-0" class="target"></span>[https://www.python.org/dev/peps/pep-3119 PEP 3119] 中所述; 请参阅 PEP 了解为什么将其添加到 Python 中。 (另请参阅 <span id="index-1" class="target"></span>[https://www.python.org/dev/peps/pep-3141 PEP 3141] 和 [[../numbers#module-numbers|numbers]] 模块,了解基于 ABC 的数字的类型层次结构。) | |
− | + | ||
+ | [[../collections#module-collections|collections]] 模块有一些从 ABC 派生的具体类; 当然,这些还可以进一步推导出来。 此外,[[../collections.abc#module-collections|collections.abc]] 子模块有一些 ABC,可用于测试类或实例是否提供特定接口,例如,是否可散列或是否是映射。 | ||
+ | |||
+ | 该模块提供了用于定义 ABC 的元类 [[#abc.ABCMeta|ABCMeta]] 和用于通过继承交替定义 ABC 的辅助类 [[#abc.ABC|ABC]]: | ||
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">ABC</span></span></dt> |
− | <dd><p> | + | <dd><p>具有 [[#abc.ABCMeta|ABCMeta]] 作为其元类的辅助类。 使用这个类,可以通过简单地从 [[#abc.ABC|ABC]] 派生来创建抽象基类,避免有时混淆元类的用法,例如:</p> |
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">from abc import ABC |
class MyABC(ABC): | class MyABC(ABC): | ||
− | pass</ | + | pass</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>请注意,[[#abc.ABC|ABC]] 的类型仍然是 [[#abc.ABCMeta|ABCMeta]],因此从 [[#abc.ABC|ABC]] 继承需要有关元类使用的常规预防措施,因为多重继承可能会导致元类冲突。 也可以通过传递 metaclass 关键字并直接使用 [[#abc.ABCMeta|ABCMeta]] 来定义抽象基类,例如:</p> |
− | |||
− | metaclass | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">from abc import ABCMeta |
class MyABC(metaclass=ABCMeta): | class MyABC(metaclass=ABCMeta): | ||
− | pass</ | + | pass</syntaxhighlight> |
</div> | </div> | ||
第56行: | 第46行: | ||
<div class="versionadded"> | <div class="versionadded"> | ||
− | <p><span class="versionmodified added">3.4 | + | <p><span class="versionmodified added">3.4 版中的新功能。</span></p> |
</div></dd></dl> | </div></dd></dl> | ||
<dl> | <dl> | ||
− | <dt>''class'' < | + | <dt>''<span class="pre">class</span>'' <span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">ABCMeta</span></span></dt> |
− | <dd><p> | + | <dd><p>用于定义抽象基类 (ABC) 的元类。</p> |
− | <p> | + | <p>使用这个元类来创建一个 ABC。 ABC 可以直接子类化,然后充当混合类。 您还可以将不相关的具体类(甚至内置类)和不相关的 ABC 注册为“虚拟子类”——这些及其后代将被内置 [[../functions#issubclass|issubclass()]] 函数视为注册 ABC 的子类,但注册 ABC 不会出现在他们的 MRO(方法解析顺序)中,注册 ABC 定义的方法实现也不会被调用(甚至不能通过 [[../functions#super|super()]])。 [[#id4|1]]</p> |
− | + | <p>使用 [[#abc.ABCMeta|ABCMeta]] 元类创建的类具有以下方法:</p> | |
− | |||
− | |||
− | ABC | ||
− | |||
− | |||
− | [[../functions#super| | ||
− | <p> | ||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">register</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">subclass</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>注册 ''subclass'' 作为这个 ABC 的“虚拟子类”。 例如:</p> |
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">from abc import ABC |
class MyABC(ABC): | class MyABC(ABC): | ||
第88行: | 第70行: | ||
assert issubclass(tuple, MyABC) | assert issubclass(tuple, MyABC) | ||
− | assert isinstance((), MyABC)</ | + | assert isinstance((), MyABC)</syntaxhighlight> |
</div> | </div> | ||
第95行: | 第77行: | ||
<div class="versionchanged"> | <div class="versionchanged"> | ||
− | <p><span class="versionmodified changed">在 3.3 | + | <p><span class="versionmodified changed"> 在 3.3 版更改: </span> 返回注册的子类,以允许用作类装饰器。</p> |
</div> | </div> | ||
<div class="versionchanged"> | <div class="versionchanged"> | ||
− | <p><span class="versionmodified changed"> | + | <p><span class="versionmodified changed"> 3.4 版更改: </span> 要检测对 [[#abc.ABCMeta.register|register()]] 的调用,可以使用 [[#abc.get_cache_token|get_cache_token()]] 函数。</p> |
− | [[#abc.get_cache_token| | ||
</div></dd></dl> | </div></dd></dl> | ||
− | <p> | + | <p>您还可以在抽象基类中覆盖此方法:</p> |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-name descname"><span class="pre">__subclasshook__</span></span><span class="sig-paren">(</span>''<span class="n"><span class="pre">subclass</span></span>''<span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>(必须定义为类方法。)</p> |
− | <p> | + | <p>检查 ''subclass'' 是否被认为是这个 ABC 的子类。 这意味着您可以进一步自定义 <code>issubclass</code> 的行为,而无需在要考虑 ABC 子类的每个类上调用 [[#abc.ABCMeta.register|register()]]。 (此类方法是从 ABC 的 <code>__subclasscheck__()</code> 方法调用的。)</p> |
− | + | <p>此方法应返回 <code>True</code>、<code>False</code> 或 <code>NotImplemented</code>。 如果它返回 <code>True</code>,则 ''子类'' 被视为此 ABC 的子类。 如果它返回 <code>False</code>,则 ''子类'' 不被视为此 ABC 的子类,即使它通常是一个子类。 如果它返回 <code>NotImplemented</code>,子类检查将继续使用通常的机制。</p></dd></dl> | |
− | |||
− | |||
− | <code>__subclasscheck__()</code> | ||
− | <p> | ||
− | |||
− | |||
− | |||
− | <code>NotImplemented</code> | ||
− | |||
− | <p> | + | <p>要演示这些概念,请查看以下示例 ABC 定义:</p> |
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class Foo: |
def __getitem__(self, index): | def __getitem__(self, index): | ||
... | ... | ||
第147行: | 第119行: | ||
def __subclasshook__(cls, C): | def __subclasshook__(cls, C): | ||
if cls is MyIterable: | if cls is MyIterable: | ||
− | if any( | + | if any("__iter__" in B.__dict__ for B in C.__mro__): |
return True | return True | ||
return NotImplemented | return NotImplemented | ||
− | MyIterable.register(Foo)</ | + | MyIterable.register(Foo)</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>ABC <code>MyIterable</code> 将标准可迭代方法 [[../stdtypes#iterator|__iter__()]] 定义为抽象方法。 这里给出的实现仍然可以从子类中调用。 <code>get_iterator()</code> 方法也是 <code>MyIterable</code> 抽象基类的一部分,但它不必在非抽象派生类中被覆盖。</p> |
− | [[../stdtypes#iterator| | + | <p>此处定义的 [[#abc.ABCMeta.__subclasshook__|__subclasshook__()]] 类方法表示,任何在其 [[../stdtypes#object|__dict__]](或其基类之一的方法中)具有 [[../stdtypes#iterator|__iter__()]] 方法的类,通过 [[../stdtypes#class|__mro__]] 列表访问)也被认为是 <code>MyIterable</code>。</p> |
− | + | <p>最后,最后一行使 <code>Foo</code> 成为 <code>MyIterable</code> 的虚拟子类,即使它没有定义 [[../stdtypes#iterator|__iter__()]] 方法(它使用旧式可迭代协议,定义为 <code>__len__()</code> 和 <code>__getitem__()</code>)。 请注意,这不会使 <code>get_iterator</code> 作为 <code>Foo</code> 的方法可用,因此单独提供。</p></dd></dl> | |
− | |||
− | |||
− | <p> | ||
− | |||
− | [[../stdtypes# | ||
− | |||
− | <p> | ||
− | |||
− | |||
− | <code>__getitem__()</code> | ||
− | |||
− | + | [[#module-abc|abc]] 模块还提供了以下装饰器: | |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-prename descclassname"><span class="pre">@</span></span><span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">abstractmethod</span></span></dt> |
− | <dd><p> | + | <dd><p>指示抽象方法的装饰器。</p> |
− | <p> | + | <p>使用这个装饰器需要类的元类是 [[#abc.ABCMeta|ABCMeta]] 或者是从它派生的。 一个具有从 [[#abc.ABCMeta|ABCMeta]] 派生的元类的类不能被实例化,除非它的所有抽象方法和属性都被覆盖。 可以使用任何正常的“超级”调用机制来调用抽象方法。 [[#abc.abstractmethod|abstractmethod()]] 可用于声明属性和描述符的抽象方法。</p> |
− | + | <p>不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。 [[#abc.abstractmethod|abstractmethod()]] 只影响使用常规继承派生的子类; 使用 ABC 的 <code>register()</code> 方法注册的“虚拟子类”不受影响。</p> | |
− | [[#abc.ABCMeta| | + | <p>当 [[#abc.abstractmethod|abstractmethod()]] 与其他方法描述符结合使用时,应作为最内层装饰器使用,如下面的使用示例所示:</p> |
− | |||
− | |||
− | |||
− | <p> | ||
− | |||
− | |||
− | |||
− | <code>register()</code> | ||
− | <p> | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class C(ABC): |
@abstractmethod | @abstractmethod | ||
def my_abstract_method(self, ...): | def my_abstract_method(self, ...): | ||
第222行: | 第172行: | ||
def _set_x(self, val): | def _set_x(self, val): | ||
... | ... | ||
− | x = property(_get_x, _set_x)</ | + | x = property(_get_x, _set_x)</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>为了正确地与抽象基类机器互操作,描述符必须使用 <code>__isabstractmethod__</code> 将自己标识为抽象。 通常,如果用于组成描述符的任何方法是抽象的,则此属性应为 <code>True</code>。 例如,Python 的内置 [[../functions#property|属性]] 相当于:</p> |
− | |||
− | <code>__isabstractmethod__</code> | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class Descriptor: |
... | ... | ||
@property | @property | ||
def __isabstractmethod__(self): | def __isabstractmethod__(self): | ||
return any(getattr(f, '__isabstractmethod__', False) for | return any(getattr(f, '__isabstractmethod__', False) for | ||
− | f in (self._fget, self._fset, self._fdel))</ | + | f in (self._fget, self._fset, self._fdel))</syntaxhighlight> |
</div> | </div> | ||
第248行: | 第194行: | ||
<div class="admonition note"> | <div class="admonition note"> | ||
− | <p> | + | <p>笔记</p> |
− | <p> | + | <p>与 Java 抽象方法不同,这些抽象方法可能有一个实现。 这个实现可以通过覆盖它的类的 [[../functions#super|super()]] 机制调用。 在使用协作多重继承的框架中,这可以用作超级调用的端点。</p> |
− | |||
− | |||
− | |||
− | |||
− | |||
</div></dd></dl> | </div></dd></dl> | ||
− | + | [[#module-abc|abc]] 模块还支持以下遗留装饰器: | |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-prename descclassname"><span class="pre">@</span></span><span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">abstractclassmethod</span></span></dt> |
<dd><div class="versionadded"> | <dd><div class="versionadded"> | ||
− | <p><span class="versionmodified added">3.2 | + | <p><span class="versionmodified added">3.2 版中的新功能。</span></p> |
</div> | </div> | ||
<div class="deprecated"> | <div class="deprecated"> | ||
− | <p><span class="versionmodified deprecated">3.3 | + | <p><span class="versionmodified deprecated"> 自 3.3 版起已弃用:</span>现在可以将 [[../functions#classmethod|classmethod]] 与 [[#abc.abstractmethod|abstractmethod()]] 一起使用,使该装饰器变得多余。</p> |
− | [[#abc.abstractmethod| | ||
</div> | </div> | ||
− | <p> | + | <p>内置 [[../functions#classmethod|classmethod()]] 的子类,表示抽象类方法。 否则它类似于 [[#abc.abstractmethod|abstractmethod()]]。</p> |
− | + | <p>这种特殊情况已被弃用,因为 [[../functions#classmethod|classmethod()]] 装饰器现在在应用于抽象方法时被正确标识为抽象:</p> | |
− | <p> | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class C(ABC): |
@classmethod | @classmethod | ||
@abstractmethod | @abstractmethod | ||
def my_abstract_classmethod(cls, ...): | def my_abstract_classmethod(cls, ...): | ||
− | ...</ | + | ...</syntaxhighlight> |
</div> | </div> | ||
第293行: | 第230行: | ||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-prename descclassname"><span class="pre">@</span></span><span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">abstractstaticmethod</span></span></dt> |
<dd><div class="versionadded"> | <dd><div class="versionadded"> | ||
− | <p><span class="versionmodified added">3.2 | + | <p><span class="versionmodified added">3.2 版中的新功能。</span></p> |
</div> | </div> | ||
<div class="deprecated"> | <div class="deprecated"> | ||
− | <p><span class="versionmodified deprecated">3.3 | + | <p><span class="versionmodified deprecated"> 自 3.3 版起已弃用: </span> 现在可以将 [[../functions#staticmethod|staticmethod]] 与 [[#abc.abstractmethod|abstractmethod()]] 一起使用,使该装饰器变得多余。</p> |
− | [[#abc.abstractmethod| | ||
</div> | </div> | ||
− | <p> | + | <p>内置 [[../functions#staticmethod|staticmethod()]] 的子类,表示抽象静态方法。 否则它类似于 [[#abc.abstractmethod|abstractmethod()]]。</p> |
− | + | <p>这种特殊情况已被弃用,因为 [[../functions#staticmethod|staticmethod()]] 装饰器现在在应用于抽象方法时被正确标识为抽象:</p> | |
− | <p> | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class C(ABC): |
@staticmethod | @staticmethod | ||
@abstractmethod | @abstractmethod | ||
def my_abstract_staticmethod(...): | def my_abstract_staticmethod(...): | ||
− | ...</ | + | ...</syntaxhighlight> |
</div> | </div> | ||
第325行: | 第258行: | ||
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-prename descclassname"><span class="pre">@</span></span><span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">abstractproperty</span></span></dt> |
<dd><div class="deprecated"> | <dd><div class="deprecated"> | ||
− | <p><span class="versionmodified deprecated">3.3 | + | <p><span class="versionmodified deprecated">自 3.3 版起已弃用:</span>现在可以将 [[../functions#property|属性]] 、<code>property.getter()</code>、<code>property.setter()</code> 和 <code>property.deleter()</code> 与 [[#abc.abstractmethod|抽象方法一起使用()]],使这个装饰器变得多余。</p> |
− | <code>property.setter()</code> | ||
− | [[#abc.abstractmethod| | ||
</div> | </div> | ||
− | <p> | + | <p>内置 [[../functions#property|property()]] 的子类,表示抽象属性。</p> |
− | + | <p>这种特殊情况已被弃用,因为 [[../functions#property|property()]] 装饰器现在在应用于抽象方法时被正确标识为抽象:</p> | |
− | <p> | ||
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class C(ABC): |
@property | @property | ||
@abstractmethod | @abstractmethod | ||
def my_abstract_property(self): | def my_abstract_property(self): | ||
− | ...</ | + | ...</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>上面的例子定义了一个只读属性; 您还可以通过适当地将一个或多个底层方法标记为抽象来定义读写抽象属性:</p> |
− | |||
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class C(ABC): |
@property | @property | ||
def x(self): | def x(self): | ||
第366行: | 第292行: | ||
@abstractmethod | @abstractmethod | ||
def x(self, val): | def x(self, val): | ||
− | ...</ | + | ...</syntaxhighlight> |
</div> | </div> | ||
</div> | </div> | ||
− | <p> | + | <p>如果只有一些组件是抽象的,则只需更新这些组件以在子类中创建具体属性:</p> |
− | |||
<div class="highlight-python3 notranslate"> | <div class="highlight-python3 notranslate"> | ||
<div class="highlight"> | <div class="highlight"> | ||
− | < | + | <syntaxhighlight lang="python3">class D(C): |
@C.x.setter | @C.x.setter | ||
def x(self, val): | def x(self, val): | ||
− | ...</ | + | ...</syntaxhighlight> |
</div> | </div> | ||
第386行: | 第311行: | ||
</div></dd></dl> | </div></dd></dl> | ||
− | + | [[#module-abc|abc]] 模块还提供以下功能: | |
<dl> | <dl> | ||
− | <dt>< | + | <dt><span class="sig-prename descclassname"><span class="pre">abc.</span></span><span class="sig-name descname"><span class="pre">get_cache_token</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span></dt> |
− | <dd><p> | + | <dd><p>返回当前抽象基类缓存令牌。</p> |
− | <p> | + | <p>令牌是一个不透明的对象(支持相等性测试),用于标识虚拟子类的抽象基类缓存的当前版本。 在任何 ABC 上每次调用 [[#abc.ABCMeta.register|ABCMeta.register()]] 时,令牌都会发生变化。</p> |
− | |||
− | |||
<div class="versionadded"> | <div class="versionadded"> | ||
− | <p><span class="versionmodified added">3.4 | + | <p><span class="versionmodified added">3.4 版中的新功能。</span></p> |
</div></dd></dl> | </div></dd></dl> | ||
− | + | 脚注 | |
+ | |||
+ | ; <span class="brackets">[[#id3|1]]</span> | ||
+ | : C++ 程序员应该注意 Python 的虚拟基类概念与 C++ 的不同。 | ||
+ | |||
+ | |||
+ | </div> | ||
+ | <div class="clearer"> | ||
− | |||
− | |||
</div> | </div> | ||
− | [[Category:Python 3.9 | + | [[Category:Python 3.9 文档]] |
2021年10月31日 (日) 04:51的最新版本
abc — 抽象基类
源代码: :source:`Lib/abc.py`
该模块提供了在 Python 中定义 抽象基类 (ABC) 的基础结构,如 PEP 3119 中所述; 请参阅 PEP 了解为什么将其添加到 Python 中。 (另请参阅 PEP 3141 和 numbers 模块,了解基于 ABC 的数字的类型层次结构。)
collections 模块有一些从 ABC 派生的具体类; 当然,这些还可以进一步推导出来。 此外,collections.abc 子模块有一些 ABC,可用于测试类或实例是否提供特定接口,例如,是否可散列或是否是映射。
该模块提供了用于定义 ABC 的元类 ABCMeta 和用于通过继承交替定义 ABC 的辅助类 ABC:
- class abc.ABC
具有 ABCMeta 作为其元类的辅助类。 使用这个类,可以通过简单地从 ABC 派生来创建抽象基类,避免有时混淆元类的用法,例如:
请注意,ABC 的类型仍然是 ABCMeta,因此从 ABC 继承需要有关元类使用的常规预防措施,因为多重继承可能会导致元类冲突。 也可以通过传递 metaclass 关键字并直接使用 ABCMeta 来定义抽象基类,例如:
3.4 版中的新功能。
- class abc.ABCMeta
用于定义抽象基类 (ABC) 的元类。
使用这个元类来创建一个 ABC。 ABC 可以直接子类化,然后充当混合类。 您还可以将不相关的具体类(甚至内置类)和不相关的 ABC 注册为“虚拟子类”——这些及其后代将被内置 issubclass() 函数视为注册 ABC 的子类,但注册 ABC 不会出现在他们的 MRO(方法解析顺序)中,注册 ABC 定义的方法实现也不会被调用(甚至不能通过 super())。 1
使用 ABCMeta 元类创建的类具有以下方法:
- register(subclass)
注册 subclass 作为这个 ABC 的“虚拟子类”。 例如:
在 3.3 版更改: 返回注册的子类,以允许用作类装饰器。
3.4 版更改: 要检测对 register() 的调用,可以使用 get_cache_token() 函数。
您还可以在抽象基类中覆盖此方法:
- __subclasshook__(subclass)
(必须定义为类方法。)
检查 subclass 是否被认为是这个 ABC 的子类。 这意味着您可以进一步自定义
issubclass
的行为,而无需在要考虑 ABC 子类的每个类上调用 register()。 (此类方法是从 ABC 的__subclasscheck__()
方法调用的。)此方法应返回
True
、False
或NotImplemented
。 如果它返回True
,则 子类 被视为此 ABC 的子类。 如果它返回False
,则 子类 不被视为此 ABC 的子类,即使它通常是一个子类。 如果它返回NotImplemented
,子类检查将继续使用通常的机制。
要演示这些概念,请查看以下示例 ABC 定义:
ABC
MyIterable
将标准可迭代方法 __iter__() 定义为抽象方法。 这里给出的实现仍然可以从子类中调用。get_iterator()
方法也是MyIterable
抽象基类的一部分,但它不必在非抽象派生类中被覆盖。此处定义的 __subclasshook__() 类方法表示,任何在其 __dict__(或其基类之一的方法中)具有 __iter__() 方法的类,通过 __mro__ 列表访问)也被认为是
MyIterable
。最后,最后一行使
Foo
成为MyIterable
的虚拟子类,即使它没有定义 __iter__() 方法(它使用旧式可迭代协议,定义为__len__()
和__getitem__()
)。 请注意,这不会使get_iterator
作为Foo
的方法可用,因此单独提供。
abc 模块还提供了以下装饰器:
- @abc.abstractmethod
指示抽象方法的装饰器。
使用这个装饰器需要类的元类是 ABCMeta 或者是从它派生的。 一个具有从 ABCMeta 派生的元类的类不能被实例化,除非它的所有抽象方法和属性都被覆盖。 可以使用任何正常的“超级”调用机制来调用抽象方法。 abstractmethod() 可用于声明属性和描述符的抽象方法。
不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。 abstractmethod() 只影响使用常规继承派生的子类; 使用 ABC 的
register()
方法注册的“虚拟子类”不受影响。当 abstractmethod() 与其他方法描述符结合使用时,应作为最内层装饰器使用,如下面的使用示例所示:
为了正确地与抽象基类机器互操作,描述符必须使用
__isabstractmethod__
将自己标识为抽象。 通常,如果用于组成描述符的任何方法是抽象的,则此属性应为True
。 例如,Python 的内置 属性 相当于:笔记
与 Java 抽象方法不同,这些抽象方法可能有一个实现。 这个实现可以通过覆盖它的类的 super() 机制调用。 在使用协作多重继承的框架中,这可以用作超级调用的端点。
abc 模块还支持以下遗留装饰器:
- @abc.abstractclassmethod
3.2 版中的新功能。
自 3.3 版起已弃用:现在可以将 classmethod 与 abstractmethod() 一起使用,使该装饰器变得多余。
内置 classmethod() 的子类,表示抽象类方法。 否则它类似于 abstractmethod()。
这种特殊情况已被弃用,因为 classmethod() 装饰器现在在应用于抽象方法时被正确标识为抽象:
- @abc.abstractstaticmethod
3.2 版中的新功能。
自 3.3 版起已弃用: 现在可以将 staticmethod 与 abstractmethod() 一起使用,使该装饰器变得多余。
内置 staticmethod() 的子类,表示抽象静态方法。 否则它类似于 abstractmethod()。
这种特殊情况已被弃用,因为 staticmethod() 装饰器现在在应用于抽象方法时被正确标识为抽象:
- @abc.abstractproperty
自 3.3 版起已弃用:现在可以将 属性 、
property.getter()
、property.setter()
和property.deleter()
与 抽象方法一起使用(),使这个装饰器变得多余。内置 property() 的子类,表示抽象属性。
这种特殊情况已被弃用,因为 property() 装饰器现在在应用于抽象方法时被正确标识为抽象:
上面的例子定义了一个只读属性; 您还可以通过适当地将一个或多个底层方法标记为抽象来定义读写抽象属性:
如果只有一些组件是抽象的,则只需更新这些组件以在子类中创建具体属性:
abc 模块还提供以下功能:
- abc.get_cache_token()
返回当前抽象基类缓存令牌。
令牌是一个不透明的对象(支持相等性测试),用于标识虚拟子类的抽象基类缓存的当前版本。 在任何 ABC 上每次调用 ABCMeta.register() 时,令牌都会发生变化。
3.4 版中的新功能。
脚注
- 1
- C++ 程序员应该注意 Python 的虚拟基类概念与 C++ 的不同。