2019-04-21 11:50:48 +08:00

99 lines
33 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="body" role="main"><div class="section" id="module-abc"><h1><span class="yiyi-st" id="yiyi-10">29.7. <a class="reference internal" href="#module-abc" title="abc: Abstract base classes according to PEP 3119."><code class="xref py py-mod docutils literal"><span class="pre">abc</span></code></a> - 抽象基类</span></h1><p><span class="yiyi-st" id="yiyi-11"><strong>源代码:</strong> <a class="reference external" href="https://hg.python.org/cpython/file/3.5/Lib/abc.py">Lib / abc.py</a></span></p><p><span class="yiyi-st" id="yiyi-12">此模块提供了用于定义Python中<a class="reference internal" href="../glossary.html#term-abstract-base-class"><span class="xref std std-term">抽象基类</span></a>ABCs的基础结构<span class="target" id="index-0"></span> <a class="pep reference external" href="https://www.python.org/dev/peps/pep-3119"><strong>PEP 3119</strong></a>请参阅PEP为什么这被添加到Python。</span><span class="yiyi-st" id="yiyi-13">有关基于ABC的数字的类型层次结构请参见<span class="target" id="index-1"></span> <a class="pep reference external" href="https://www.python.org/dev/peps/pep-3141"><strong>PEP 3141</strong></a><a class="reference internal" href="numbers.html#module-numbers" title="numbers: Numeric abstract base classes (Complex, Real, Integral, etc.)."><code class="xref py py-mod docutils literal"><span class="pre">数字</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-14"><a class="reference internal" href="collections.html#module-collections" title="collections: Container datatypes"><code class="xref py py-mod docutils literal"><span class="pre">容器</span></code></a>模块有一些从ABCs派生的具体类这些当然可以进一步推导出来。</span><span class="yiyi-st" id="yiyi-15">此外,<a class="reference internal" href="collections.abc.html#module-collections.abc" title="collections.abc: Abstract base classes for containers"><code class="xref py py-mod docutils literal"><span class="pre">collections.abc</span></code></a>子模块具有一些可用于测试类或实例是否提供特定接口的ABC例如它是哈希表还是映射。</span></p><p><span class="yiyi-st" id="yiyi-16">此模块提供以下类:</span></p><dl class="class"><dt id="abc.ABCMeta"><span class="yiyi-st" id="yiyi-17"> <em class="property">class </em><code class="descclassname">abc.</code><code class="descname">ABCMeta</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-18">用于定义抽象基类ABC的元类。</span></p><p><span class="yiyi-st" id="yiyi-19">使用此元类创建ABC。</span><span class="yiyi-st" id="yiyi-20">ABC可以直接子类化然后充当混合类。</span><span class="yiyi-st" id="yiyi-21">你还可以将不相关的具体类甚至内建类和不相关的ABCs注册为“虚拟子类” - 这些及其后代将被内建<a class="reference internal" href="functions.html#issubclass" title="issubclass"><code class="xref py py-func docutils literal"><span class="pre">issubclass()</span></code></a>函数视为注册ABC的子类但是注册的ABC不会出现在他们的MRO方法解析顺序注册的ABC定义的方法实现也不能调用甚至不能通过<a class="reference internal" href="functions.html#super" title="super"><code class="xref py py-func docutils literal"><span class="pre">super()</span></code></a>)。</span><span class="yiyi-st" id="yiyi-22"><a class="footnote-reference" href="#id2" id="id1"> [1] T0&gt;</a></span></p><p><span class="yiyi-st" id="yiyi-23">使用<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>的元类创建的类具有以下方法:</span></p><dl class="method"><dt id="abc.ABCMeta.register"><span class="yiyi-st" id="yiyi-24"> <code class="descname">register</code><span class="sig-paren">(</span><em>subclass</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-25"><em>子类</em>注册为此ABC的“虚拟子类”。</span><span class="yiyi-st" id="yiyi-26">例如:</span></p><pre><code class="language-python"><span></span><span class="kn">from</span> <span class="nn">abc</span> <span class="k">import</span> <span class="n">ABCMeta</span>
<span class="k">class</span> <span class="nc">MyABC</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="k">pass</span>
<span class="n">MyABC</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="nb">tuple</span><span class="p">)</span>
<span class="k">assert</span> <span class="nb">issubclass</span><span class="p">(</span><span class="nb">tuple</span><span class="p">,</span> <span class="n">MyABC</span><span class="p">)</span>
<span class="k">assert</span> <span class="nb">isinstance</span><span class="p">((),</span> <span class="n">MyABC</span><span class="p">)</span>
</code></pre><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-27"><span class="versionmodified">在版本3.3中更改:</span>返回已注册的子类,以允许用作类装饰器。</span></p></div><div class="versionchanged"><p><span class="yiyi-st" id="yiyi-28"><span class="versionmodified">在版本3.4中更改:</span>要检测对<a class="reference internal" href="#abc.ABCMeta.register" title="abc.ABCMeta.register"><code class="xref py py-meth docutils literal"><span class="pre">register()</span></code></a>的调用,您可以使用<a class="reference internal" href="#abc.get_cache_token" title="abc.get_cache_token"><code class="xref py py-func docutils literal"><span class="pre">get_cache_token()</span></code></a>函数。</span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-29">您还可以在抽象基类中覆盖此方法:</span></p><dl class="method"><dt id="abc.ABCMeta.__subclasshook__"><span class="yiyi-st" id="yiyi-30"> <code class="descname">__subclasshook__</code><span class="sig-paren">(</span><em>subclass</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-31">(必须定义为类方法。)</span></p><p><span class="yiyi-st" id="yiyi-32">检查<em>子类</em>是否被认为是此ABC的子类。</span><span class="yiyi-st" id="yiyi-33">这意味着您可以进一步自定义<code class="docutils literal"><span class="pre">issubclass</span></code>的行为而无需在每个想要考虑ABC子类的类中调用<a class="reference internal" href="#abc.ABCMeta.register" title="abc.ABCMeta.register"><code class="xref py py-meth docutils literal"><span class="pre">register()</span></code></a></span><span class="yiyi-st" id="yiyi-34">此类方法从ABC的<code class="xref py py-meth docutils literal"><span class="pre">__subclasscheck__()</span></code>方法调用。)</span></p><p><span class="yiyi-st" id="yiyi-35">此方法应返回<code class="docutils literal"><span class="pre">True</span></code><code class="docutils literal"><span class="pre">False</span></code><code class="docutils literal"><span class="pre">NotImplemented</span></code></span><span class="yiyi-st" id="yiyi-36">如果返回<code class="docutils literal"><span class="pre">True</span></code>,则<em>子类</em>被认为是此ABC的子类。</span><span class="yiyi-st" id="yiyi-37">如果它返回<code class="docutils literal"><span class="pre">False</span></code>,则<em>子类</em>不被认为是此ABC的子类即使它通常是一个。</span><span class="yiyi-st" id="yiyi-38">如果返回<code class="docutils literal"><span class="pre">NotImplemented</span></code>,则子类检查以常用机制继续。</span></p></dd></dl><p><span class="yiyi-st" id="yiyi-39">为了演示这些概念看看这个例子ABC定义</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">Foo</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">index</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">__len__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">def</span> <span class="nf">get_iterator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">iter</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">MyIterable</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">__iter__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">while</span> <span class="kc">False</span><span class="p">:</span>
<span class="k">yield</span> <span class="kc">None</span>
<span class="k">def</span> <span class="nf">get_iterator</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__iter__</span><span class="p">()</span>
<span class="nd">@classmethod</span>
<span class="k">def</span> <span class="nf">__subclasshook__</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="n">C</span><span class="p">):</span>
<span class="k">if</span> <span class="n">cls</span> <span class="ow">is</span> <span class="n">MyIterable</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">any</span><span class="p">(</span><span class="s2">"__iter__"</span> <span class="ow">in</span> <span class="n">B</span><span class="o">.</span><span class="n">__dict__</span> <span class="k">for</span> <span class="n">B</span> <span class="ow">in</span> <span class="n">C</span><span class="o">.</span><span class="n">__mro__</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">return</span> <span class="bp">NotImplemented</span>
<span class="n">MyIterable</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Foo</span><span class="p">)</span>
</code></pre><p><span class="yiyi-st" id="yiyi-40">ABC <code class="docutils literal"><span class="pre">MyIterable</span></code>定义标准可迭代方法<a class="reference internal" href="stdtypes.html#iterator.__iter__" title="iterator.__iter__"><code class="xref py py-meth docutils literal"><span class="pre">__iter__()</span></code></a>作为抽象方法。</span><span class="yiyi-st" id="yiyi-41">这里给出的实现仍然可以从子类调用。</span><span class="yiyi-st" id="yiyi-42"><code class="xref py py-meth docutils literal"><span class="pre">get_iterator()</span></code>方法也是<code class="docutils literal"><span class="pre">MyIterable</span></code>抽象基类的一部分,但它不必在非抽象派生类中被覆盖。</span></p><p><span class="yiyi-st" id="yiyi-43">The <a class="reference internal" href="#abc.ABCMeta.__subclasshook__" title="abc.ABCMeta.__subclasshook__"><code class="xref py py-meth docutils literal"><span class="pre">__subclasshook__()</span></code></a> class method defined here says that any class that has an <a class="reference internal" href="stdtypes.html#iterator.__iter__" title="iterator.__iter__"><code class="xref py py-meth docutils literal"><span class="pre">__iter__()</span></code></a> method in its <a class="reference internal" href="stdtypes.html#object.__dict__" title="object.__dict__"><code class="xref py py-attr docutils literal"><span class="pre">__dict__</span></code></a> (or in that of one of its base classes, accessed via the <a class="reference internal" href="stdtypes.html#class.__mro__" title="class.__mro__"><code class="xref py py-attr docutils literal"><span class="pre">__mro__</span></code></a> list) is considered a <code class="docutils literal"><span class="pre">MyIterable</span></code> too.</span></p><p><span class="yiyi-st" id="yiyi-44">最后,最后一行使<code class="docutils literal"><span class="pre">Foo</span></code><code class="docutils literal"><span class="pre">MyIterable</span></code>的虚拟子类,即使它没有定义一个<a class="reference internal" href="stdtypes.html#iterator.__iter__" title="iterator.__iter__"><code class="xref py py-meth docutils literal"><span class="pre">__iter__()</span></code></a>按照<a class="reference internal" href="../reference/datamodel.html#object.__len__" title="object.__len__"><code class="xref py py-meth docutils literal"><span class="pre">__len__()</span></code></a><a class="reference internal" href="../reference/datamodel.html#object.__getitem__" title="object.__getitem__"><code class="xref py py-meth docutils literal"><span class="pre">__getitem__()</span></code></a>定义的类型可迭代协议。</span><span class="yiyi-st" id="yiyi-45">请注意,这不会使<code class="docutils literal"><span class="pre">get_iterator</span></code>作为<code class="docutils literal"><span class="pre">Foo</span></code>的方法可用,因此它是单独提供的。</span></p></dd></dl><dl class="class"><dt id="abc.ABC"><span class="yiyi-st" id="yiyi-46"> <em class="property">class </em><code class="descclassname">abc.</code><code class="descname">ABC</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-47">一个辅助类,它具有<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>作为其元类。</span><span class="yiyi-st" id="yiyi-48">使用这个类,可以通过简单地从<a class="reference internal" href="#abc.ABC" title="abc.ABC"><code class="xref py py-class docutils literal"><span class="pre">ABC</span></code></a>派生来创建抽象基类,避免有时会混淆元类使用。</span></p><p><span class="yiyi-st" id="yiyi-49">注意,<a class="reference internal" href="#abc.ABC" title="abc.ABC"><code class="xref py py-class docutils literal"><span class="pre">ABC</span></code></a>的类型仍然是<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>,因此从<a class="reference internal" href="#abc.ABC" title="abc.ABC"><code class="xref py py-class docutils literal"><span class="pre">ABC</span></code></a>继承需要关于元类使用的通常预防措施,因为多重继承可能导致元类冲突。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-50"><span class="versionmodified">版本3.4中的新功能。</span></span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-51"><a class="reference internal" href="#module-abc" title="abc: Abstract base classes according to PEP 3119."><code class="xref py py-mod docutils literal"><span class="pre">abc</span></code></a>模块还提供以下装饰器:</span></p><dl class="function"><dt id="abc.abstractmethod"><span class="yiyi-st" id="yiyi-52"> <code class="descclassname">@</code><code class="descclassname">abc.</code><code class="descname">abstractmethod</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-53">装饰器指示抽象方法。</span></p><p><span class="yiyi-st" id="yiyi-54">使用这个装饰器需要类的元类是<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>或派生自它。</span><span class="yiyi-st" id="yiyi-55">具有从<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>派生的元类的类不能实例化,除非其所有的抽象方法和属性都被覆盖。</span><span class="yiyi-st" id="yiyi-56">抽象方法可以使用任何正常的“超级”调用机制来调用。</span><span class="yiyi-st" id="yiyi-57"><a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>可用于声明属性和描述器的抽象方法。</span></p><p><span class="yiyi-st" id="yiyi-58">动态地向类中添加抽象方法,或者在创建方法或类之后尝试修改抽象状态。</span><span class="yiyi-st" id="yiyi-59"><a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>仅影响使用常规继承导出的子类注册到ABC的<code class="xref py py-meth docutils literal"><span class="pre">register()</span></code>方法的“虚拟子类”不受影响。</span></p><p><span class="yiyi-st" id="yiyi-60"><a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>与其他方法描述器组合应用时,应将其应用为最内装饰器件,如以下用法示例所示:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_method</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">...</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@classmethod</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_classmethod</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="o">...</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@staticmethod</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_staticmethod</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_property</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@my_abstract_property</span><span class="o">.</span><span class="n">setter</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_property</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">_get_x</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">_set_x</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
<span class="o">...</span>
<span class="n">x</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">_get_x</span><span class="p">,</span> <span class="n">_set_x</span><span class="p">)</span>
</code></pre><p><span class="yiyi-st" id="yiyi-61">为了与抽象基类机制正确地互操作,描述器必须使用<code class="xref py py-attr docutils literal"><span class="pre">__isabstractmethod__</span></code>来将自身标识为抽象。</span><span class="yiyi-st" id="yiyi-62">一般来说,如果用于撰写描述器的任何方法是抽象的,则此属性应为<code class="docutils literal"><span class="pre">True</span></code></span><span class="yiyi-st" id="yiyi-63">例如Python的内建属性相当于</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">Descriptor</span><span class="p">:</span>
<span class="o">...</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">__isabstractmethod__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">any</span><span class="p">(</span><span class="nb">getattr</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="s1">'__isabstractmethod__'</span><span class="p">,</span> <span class="kc">False</span><span class="p">)</span> <span class="k">for</span>
<span class="n">f</span> <span class="ow">in</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_fget</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_fset</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_fdel</span><span class="p">))</span>
</code></pre><div class="admonition note"><p class="first admonition-title"><span class="yiyi-st" id="yiyi-64">注意</span></p><p class="last"><span class="yiyi-st" id="yiyi-65">与Java抽象方法不同这些抽象方法可能有一个实现。</span><span class="yiyi-st" id="yiyi-66">这个实现可以通过<a class="reference internal" href="functions.html#super" title="super"><code class="xref py py-func docutils literal"><span class="pre">super()</span></code></a>机制从覆盖它的类中调用。</span><span class="yiyi-st" id="yiyi-67">这可以用作使用协作多继承的框架中的超级调用的端点。</span></p></div></dd></dl><dl class="function"><dt id="abc.abstractclassmethod"><span class="yiyi-st" id="yiyi-68"> <code class="descclassname">@</code><code class="descclassname">abc.</code><code class="descname">abstractclassmethod</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-69">内建<a class="reference internal" href="functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal"><span class="pre">classmethod()</span></code></a>的子类,表示抽象类方法。</span><span class="yiyi-st" id="yiyi-70">否则它类似于<a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-71">这种特殊情况已被弃用,因为<a class="reference internal" href="functions.html#classmethod" title="classmethod"><code class="xref py py-func docutils literal"><span class="pre">classmethod()</span></code></a>装饰器在应用于抽象方法时现已正确标识为抽象:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@classmethod</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_classmethod</span><span class="p">(</span><span class="n">cls</span><span class="p">,</span> <span class="o">...</span><span class="p">):</span>
<span class="o">...</span>
</code></pre><div class="versionadded"><p><span class="yiyi-st" id="yiyi-72"><span class="versionmodified">版本3.2中的新功能。</span></span></p></div><div class="deprecated"><p><span class="yiyi-st" id="yiyi-73"><span class="versionmodified">自版本3.3后已弃用:</span>现在可以使用<a class="reference internal" href="functions.html#classmethod" title="classmethod"><code class="xref py py-class docutils literal"><span class="pre">classmethod</span></code></a><a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>,使此装饰器冗余。</span></p></div></dd></dl><dl class="function"><dt id="abc.abstractstaticmethod"><span class="yiyi-st" id="yiyi-74"> <code class="descclassname">@</code><code class="descclassname">abc.</code><code class="descname">abstractstaticmethod</code></span></dt><dd><p><span class="yiyi-st" id="yiyi-75">内建<a class="reference internal" href="functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal"><span class="pre">staticmethod()</span></code></a>的子类,表示抽象静态方法。</span><span class="yiyi-st" id="yiyi-76">否则它类似于<a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a></span></p><p><span class="yiyi-st" id="yiyi-77">这种特殊情况已被弃用,因为<a class="reference internal" href="functions.html#staticmethod" title="staticmethod"><code class="xref py py-func docutils literal"><span class="pre">staticmethod()</span></code></a>装饰器在应用于抽象方法时现在可正确识别为抽象:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@staticmethod</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_staticmethod</span><span class="p">(</span><span class="o">...</span><span class="p">):</span>
<span class="o">...</span>
</code></pre><div class="versionadded"><p><span class="yiyi-st" id="yiyi-78"><span class="versionmodified">版本3.2中的新功能。</span></span></p></div><div class="deprecated"><p><span class="yiyi-st" id="yiyi-79"><span class="versionmodified">自版本3.3后已弃用:</span>现在可以使用<a class="reference internal" href="functions.html#staticmethod" title="staticmethod"><code class="xref py py-class docutils literal"><span class="pre">staticmethod</span></code></a><a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>,使此装饰器冗余。</span></p></div></dd></dl><dl class="function"><dt id="abc.abstractproperty"><span class="yiyi-st" id="yiyi-80"> <code class="descclassname">@</code><code class="descclassname">abc.</code><code class="descname">abstractproperty</code><span class="sig-paren">(</span><em>fget=None</em>, <em>fset=None</em>, <em>fdel=None</em>, <em>doc=None</em><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-81">内建<a class="reference internal" href="functions.html#property" title="property"><code class="xref py py-func docutils literal"><span class="pre">property()</span></code></a>的子类,表示一个抽象属性。</span></p><p><span class="yiyi-st" id="yiyi-82">使用这个函数需要类的元类是<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>或派生自它。</span><span class="yiyi-st" id="yiyi-83">具有从<a class="reference internal" href="#abc.ABCMeta" title="abc.ABCMeta"><code class="xref py py-class docutils literal"><span class="pre">ABCMeta</span></code></a>派生的元类的类不能实例化,除非其所有的抽象方法和属性都被覆盖。</span><span class="yiyi-st" id="yiyi-84">可以使用任何正常的“超级”调用机制来调用抽象属性。</span></p><p><span class="yiyi-st" id="yiyi-85">这种特殊情况已被弃用,因为<a class="reference internal" href="functions.html#property" title="property"><code class="xref py py-func docutils literal"><span class="pre">property()</span></code></a>装饰器在应用于抽象方法时现已正确标识为抽象:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@property</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">my_abstract_property</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
</code></pre><p><span class="yiyi-st" id="yiyi-86">上面的例子定义了一个只读属性;您还可以通过将一个或多个底层方法适当地标记为抽象来定义读写抽象属性:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="n">metaclass</span><span class="o">=</span><span class="n">ABCMeta</span><span class="p">):</span>
<span class="nd">@property</span>
<span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="o">...</span>
<span class="nd">@x</span><span class="o">.</span><span class="n">setter</span>
<span class="nd">@abstractmethod</span>
<span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
<span class="o">...</span>
</code></pre><p><span class="yiyi-st" id="yiyi-87">如果只有一些组件是抽象的,只有那些组件需要更新以在子类中创建一个具体的属性:</span></p><pre><code class="language-python"><span></span><span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="n">C</span><span class="p">):</span>
<span class="nd">@C</span><span class="o">.</span><span class="n">x</span><span class="o">.</span><span class="n">setter</span>
<span class="k">def</span> <span class="nf">x</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">val</span><span class="p">):</span>
<span class="o">...</span>
</code></pre><div class="deprecated"><p><span class="yiyi-st" id="yiyi-88"><span class="versionmodified">Deprecated since version 3.3: </span>It is now possible to use <a class="reference internal" href="functions.html#property" title="property"><code class="xref py py-class docutils literal"><span class="pre">property</span></code></a>, <code class="xref py py-meth docutils literal"><span class="pre">property.getter()</span></code>, <code class="xref py py-meth docutils literal"><span class="pre">property.setter()</span></code> and <code class="xref py py-meth docutils literal"><span class="pre">property.deleter()</span></code> with <a class="reference internal" href="#abc.abstractmethod" title="abc.abstractmethod"><code class="xref py py-func docutils literal"><span class="pre">abstractmethod()</span></code></a>, making this decorator redundant.</span></p></div></dd></dl><p><span class="yiyi-st" id="yiyi-89"><a class="reference internal" href="#module-abc" title="abc: Abstract base classes according to PEP 3119."><code class="xref py py-mod docutils literal"><span class="pre">abc</span></code></a>模块还提供以下功能:</span></p><dl class="function"><dt id="abc.get_cache_token"><span class="yiyi-st" id="yiyi-90"> <code class="descclassname">abc.</code><code class="descname">get_cache_token</code><span class="sig-paren">(</span><span class="sig-paren">)</span></span></dt><dd><p><span class="yiyi-st" id="yiyi-91">返回当前抽象基类缓存令牌。</span></p><p><span class="yiyi-st" id="yiyi-92">令牌是一个不透明的对象(支持相等测试),用于标识虚拟子类的抽象基类缓存的当前版本。</span><span class="yiyi-st" id="yiyi-93">令牌随着对任何ABC的每个对<a class="reference internal" href="#abc.ABCMeta.register" title="abc.ABCMeta.register"><code class="xref py py-meth docutils literal"><span class="pre">ABCMeta.register()</span></code></a>的调用而改变。</span></p><div class="versionadded"><p><span class="yiyi-st" id="yiyi-94"><span class="versionmodified">版本3.4中的新功能。</span></span></p></div></dd></dl><p class="rubric"><span class="yiyi-st" id="yiyi-95">脚注</span></p><table class="docutils footnote" frame="void" id="id2" rules="none"><tbody valign="top"><tr><td class="label"><span class="yiyi-st" id="yiyi-96"><a class="fn-backref" href="#id1">[1]</a></span></td><td><span class="yiyi-st" id="yiyi-97">C ++程序员应该注意Python的虚拟基类概念与C ++不一样。</span></td></tr></tbody></table></div></div>