[code.view]

[top] / python / PyMOTW / docs / abc / index.html


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>abc – Abstract Base Classes &mdash; Python Module of the Week</title>
    <link rel="stylesheet" href="../_static/sphinxdoc.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '1.132',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <link rel="author" title="About these documents" href="../about.html" />
    <link rel="top" title="Python Module of the Week" href="../index.html" />
    <link rel="up" title="Python Runtime Services" href="../runtime_services.html" />
    <link rel="next" title="atexit – Call functions when a program is closing down" href="../atexit/index.html" />
    <link rel="prev" title="Python Runtime Services" href="../runtime_services.html" /> 
  </head>
  <body>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="right" >
          <a href="../atexit/index.html" title="atexit – Call functions when a program is closing down"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="../runtime_services.html" title="Python Runtime Services"
             accesskey="P">previous</a> |</li>
        <li><a href="../contents.html">PyMOTW</a> &raquo;</li>
          <li><a href="../runtime_services.html" accesskey="U">Python Runtime Services</a> &raquo;</li> 
      </ul>
    </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">abc &#8211; Abstract Base Classes</a><ul>
<li><a class="reference internal" href="#why-use-abstract-base-classes">Why use Abstract Base Classes?</a></li>
<li><a class="reference internal" href="#how-abcs-work">How ABCs Work</a></li>
<li><a class="reference internal" href="#registering-a-concrete-class">Registering a Concrete Class</a></li>
<li><a class="reference internal" href="#implementation-through-subclassing">Implementation Through Subclassing</a><ul>
<li><a class="reference internal" href="#incomplete-implementations">Incomplete Implementations</a></li>
</ul>
</li>
<li><a class="reference internal" href="#concrete-methods-in-abcs">Concrete Methods in ABCs</a></li>
<li><a class="reference internal" href="#abstract-properties">Abstract Properties</a></li>
<li><a class="reference internal" href="#collection-types">Collection Types</a></li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="../runtime_services.html"
                        title="previous chapter">Python Runtime Services</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="../atexit/index.html"
                        title="next chapter">atexit &#8211; Call functions when a program is closing down</a></p>
  <h3>This Page</h3>
  <ul class="this-page-menu">
    <li><a href="../_sources/abc/index.txt"
           rel="nofollow">Show Source</a></li>
  </ul>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" size="18" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="module-abc">
<span id="abc-abstract-base-classes"></span><h1>abc &#8211; Abstract Base Classes<a class="headerlink" href="#module-abc" title="Permalink to this headline">¶</a></h1>
<table class="docutils field-list" frame="void" rules="none">
<col class="field-name" />
<col class="field-body" />
<tbody valign="top">
<tr class="field"><th class="field-name">Purpose:</th><td class="field-body">Define and use abstract base classes for API checks in your code.</td>
</tr>
<tr class="field"><th class="field-name">Python Version:</th><td class="field-body">2.6</td>
</tr>
</tbody>
</table>
<div class="section" id="why-use-abstract-base-classes">
<h2>Why use Abstract Base Classes?<a class="headerlink" href="#why-use-abstract-base-classes" title="Permalink to this headline">¶</a></h2>
<p>Abstract base classes are a form of interface checking more strict
than individual <tt class="docutils literal"><span class="pre">hasattr()</span></tt> checks for particular methods.  By
defining an abstract base class, you can define a common API for a set
of subclasses.  This capability is especially useful in situations
where a third-party is going to provide implementations, such as with
plugins to an application, but can also aid you when working on a
large team or with a large code-base where keeping all classes in your
head at the same time is difficult or not possible.</p>
</div>
<div class="section" id="how-abcs-work">
<h2>How ABCs Work<a class="headerlink" href="#how-abcs-work" title="Permalink to this headline">¶</a></h2>
<p><a class="reference internal" href="#module-abc" title="abc: Abstract Base Classes"><tt class="xref py py-mod docutils literal"><span class="pre">abc</span></tt></a> works by marking methods of the base class as abstract, and
then registering concrete classes as implementations of the abstract
base.  If your code requires a particular API, you can use
<tt class="docutils literal"><span class="pre">issubclass()</span></tt> or <tt class="docutils literal"><span class="pre">isinstance()</span></tt> to check an object against the
abstract class.</p>
<p>Let&#8217;s start by defining an abstract base class to represent the API of
a set of plugins for saving and loading data.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>

<span class="k">class</span> <span class="nc">PluginBase</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
    
    <span class="nd">@abc.abstractmethod</span>
    <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Retrieve data from the input source and return an object.&quot;&quot;&quot;</span>
        <span class="k">return</span>
    
    <span class="nd">@abc.abstractmethod</span>
    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Save the data object to the output.&quot;&quot;&quot;</span>
        <span class="k">return</span>
</pre></div>
</div>
</div>
<div class="section" id="registering-a-concrete-class">
<h2>Registering a Concrete Class<a class="headerlink" href="#registering-a-concrete-class" title="Permalink to this headline">¶</a></h2>
<p>There are two ways to indicate that a concrete class implements an
abstract: register the class with the abc or subclass directly from
the abc.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">from</span> <span class="nn">abc_base</span> <span class="kn">import</span> <span class="n">PluginBase</span>

<span class="k">class</span> <span class="nc">RegisteredImplementation</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">input</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
    
    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="n">PluginBase</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">RegisteredImplementation</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;Subclass:&#39;</span><span class="p">,</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">RegisteredImplementation</span><span class="p">,</span> <span class="n">PluginBase</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&#39;Instance:&#39;</span><span class="p">,</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">RegisteredImplementation</span><span class="p">(),</span> <span class="n">PluginBase</span><span class="p">)</span>
</pre></div>
</div>
<p>In this example the <tt class="docutils literal"><span class="pre">PluginImplementation</span></tt> is not derived from
<tt class="docutils literal"><span class="pre">PluginBase</span></tt>, but is registered as implementing the <tt class="docutils literal"><span class="pre">PluginBase</span></tt>
API.</p>
<div class="highlight-python"><pre>$ python abc_register.py

Subclass: True
Instance: True</pre>
</div>
</div>
<div class="section" id="implementation-through-subclassing">
<h2>Implementation Through Subclassing<a class="headerlink" href="#implementation-through-subclassing" title="Permalink to this headline">¶</a></h2>
<p>By subclassing directly from the base, we can avoid the need to
register the class explicitly.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">from</span> <span class="nn">abc_base</span> <span class="kn">import</span> <span class="n">PluginBase</span>

<span class="k">class</span> <span class="nc">SubclassImplementation</span><span class="p">(</span><span class="n">PluginBase</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">input</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
    
    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;Subclass:&#39;</span><span class="p">,</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">SubclassImplementation</span><span class="p">,</span> <span class="n">PluginBase</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&#39;Instance:&#39;</span><span class="p">,</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">SubclassImplementation</span><span class="p">(),</span> <span class="n">PluginBase</span><span class="p">)</span>
</pre></div>
</div>
<p>In this case the normal Python class management is used to recognize
<tt class="docutils literal"><span class="pre">PluginImplementation</span></tt> as implementing the abstract <tt class="docutils literal"><span class="pre">PluginBase</span></tt>.</p>
<div class="highlight-python"><pre>$ python abc_subclass.py

Subclass: True
Instance: True</pre>
</div>
<p>A side-effect of using direct subclassing is it is possible to find
all of the implementations of your plugin by asking the base class for
the list of known classes derived from it (this is not an abc feature,
all classes can do this).</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">from</span> <span class="nn">abc_base</span> <span class="kn">import</span> <span class="n">PluginBase</span>
<span class="kn">import</span> <span class="nn">abc_subclass</span>
<span class="kn">import</span> <span class="nn">abc_register</span>

<span class="k">for</span> <span class="n">sc</span> <span class="ow">in</span> <span class="n">PluginBase</span><span class="o">.</span><span class="n">__subclasses__</span><span class="p">():</span>
    <span class="k">print</span> <span class="n">sc</span><span class="o">.</span><span class="n">__name__</span>
</pre></div>
</div>
<p>Notice that even though <tt class="docutils literal"><span class="pre">abc_register</span></tt> is imported,
<tt class="docutils literal"><span class="pre">RegisteredImplementation</span></tt> is not among the list of subclasses
because it is not actually derived from the base.</p>
<div class="highlight-python"><pre>$ python abc_find_subclasses.py

SubclassImplementation</pre>
</div>
<p>Dr. André Roberge <a class="reference external" href="http://us.pycon.org/2009/conference/schedule/event/47/">has described</a> using this
capability to discover plugins by importing all of the modules in a
directory dynamically and then looking at the subclass list to find
the implementation classes.</p>
<div class="section" id="incomplete-implementations">
<h3>Incomplete Implementations<a class="headerlink" href="#incomplete-implementations" title="Permalink to this headline">¶</a></h3>
<p>Another benefit of subclassing directly from your abstract base class
is that the subclass cannot be instantiated unless it fully implements
the abstract portion of the API.  This can keep half-baked
implementations from triggering unexpected errors at runtime.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">from</span> <span class="nn">abc_base</span> <span class="kn">import</span> <span class="n">PluginBase</span>

<span class="k">class</span> <span class="nc">IncompleteImplementation</span><span class="p">(</span><span class="n">PluginBase</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">output</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="k">return</span> <span class="n">output</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="n">PluginBase</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">IncompleteImplementation</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;Subclass:&#39;</span><span class="p">,</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">IncompleteImplementation</span><span class="p">,</span> <span class="n">PluginBase</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&#39;Instance:&#39;</span><span class="p">,</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">IncompleteImplementation</span><span class="p">(),</span> <span class="n">PluginBase</span><span class="p">)</span>
</pre></div>
</div>
<div class="highlight-python"><pre>$ python abc_incomplete.py

Subclass: True
Instance:
Traceback (most recent call last):
  File "abc_incomplete.py", line 22, in &lt;module&gt;
    print 'Instance:', isinstance(IncompleteImplementation(), PluginBase)
TypeError: Can't instantiate abstract class IncompleteImplementation with abstract methods load</pre>
</div>
</div>
</div>
<div class="section" id="concrete-methods-in-abcs">
<h2>Concrete Methods in ABCs<a class="headerlink" href="#concrete-methods-in-abcs" title="Permalink to this headline">¶</a></h2>
<p>Although a concrete class must provide an implementation of an
abstract methods, the abstract base class can also provide an
implementation that can be invoked via <tt class="docutils literal"><span class="pre">super()</span></tt>.  This lets you
re-use common logic by placing it in the base class, but force
subclasses to provide an overriding method with (potentially) custom
logic.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>
<span class="kn">from</span> <span class="nn">cStringIO</span> <span class="kn">import</span> <span class="n">StringIO</span>

<span class="k">class</span> <span class="nc">ABCWithConcreteImplementation</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
    
    <span class="nd">@abc.abstractmethod</span>
    <span class="k">def</span> <span class="nf">retrieve_values</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
        <span class="k">print</span> <span class="s">&#39;base class reading data&#39;</span>
        <span class="k">return</span> <span class="nb">input</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>

<span class="k">class</span> <span class="nc">ConcreteOverride</span><span class="p">(</span><span class="n">ABCWithConcreteImplementation</span><span class="p">):</span>
    
    <span class="k">def</span> <span class="nf">retrieve_values</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">input</span><span class="p">):</span>
        <span class="n">base_data</span> <span class="o">=</span> <span class="nb">super</span><span class="p">(</span><span class="n">ConcreteOverride</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">retrieve_values</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span>
        <span class="k">print</span> <span class="s">&#39;subclass sorting data&#39;</span>
        <span class="n">response</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">base_data</span><span class="o">.</span><span class="n">splitlines</span><span class="p">())</span>
        <span class="k">return</span> <span class="n">response</span>

<span class="nb">input</span> <span class="o">=</span> <span class="n">StringIO</span><span class="p">(</span><span class="s">&quot;&quot;&quot;line one</span>
<span class="s">line two</span>
<span class="s">line three</span>
<span class="s">&quot;&quot;&quot;</span><span class="p">)</span>

<span class="n">reader</span> <span class="o">=</span> <span class="n">ConcreteOverride</span><span class="p">()</span>
<span class="k">print</span> <span class="n">reader</span><span class="o">.</span><span class="n">retrieve_values</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span>
<span class="k">print</span>
</pre></div>
</div>
<p>Since <tt class="docutils literal"><span class="pre">ABCWithConcreteImplementation</span></tt> is an abstract base class, it
isn&#8217;t possible to instantiate it to use it directly.  Subclasses
<em>must</em> provide an override for <tt class="docutils literal"><span class="pre">retrieve_values()</span></tt>, and in this case
the concrete class massages the data before returning it at all.</p>
<div class="highlight-python"><pre>$ python abc_concrete_method.py

base class reading data
subclass sorting data
['line one', 'line three', 'line two']</pre>
</div>
</div>
<div class="section" id="abstract-properties">
<span id="abc-abstract-properties"></span><h2>Abstract Properties<a class="headerlink" href="#abstract-properties" title="Permalink to this headline">¶</a></h2>
<p>If your API specification includes attributes in addition to methods,
you can require the attributes in concrete classes by defining them
with <tt class="docutils literal"><span class="pre">&#64;abstractproperty</span></tt>.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>

<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
    
    <span class="nd">@abc.abstractproperty</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;Should never get here&#39;</span>


<span class="k">class</span> <span class="nc">Implementation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
    
    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;concrete property&#39;</span>


<span class="k">try</span><span class="p">:</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">Base</span><span class="p">()</span>
    <span class="k">print</span> <span class="s">&#39;Base.value:&#39;</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">value</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">err</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;ERROR:&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>

<span class="n">i</span> <span class="o">=</span> <span class="n">Implementation</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;Implementation.value:&#39;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">value</span>
</pre></div>
</div>
<p>The <tt class="docutils literal"><span class="pre">Base</span></tt> class in the example cannot be instantiated because it
has only an abstract version of the property getter method.</p>
<div class="highlight-python"><pre>$ python abc_abstractproperty.py

ERROR: Can't instantiate abstract class Base with abstract methods value
Implementation.value: concrete property</pre>
</div>
<p>You can also define abstract read/write properties.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>

<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
    
    <span class="k">def</span> <span class="nf">value_getter</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;Should never see this&#39;</span>
    
    <span class="k">def</span> <span class="nf">value_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">newvalue</span><span class="p">):</span>
        <span class="k">return</span>

    <span class="n">value</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">abstractproperty</span><span class="p">(</span><span class="n">value_getter</span><span class="p">,</span> <span class="n">value_setter</span><span class="p">)</span>


<span class="k">class</span> <span class="nc">PartialImplementation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
    
    <span class="nd">@abc.abstractproperty</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;Read-only&#39;</span>


<span class="k">class</span> <span class="nc">Implementation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
    
    <span class="n">_value</span> <span class="o">=</span> <span class="s">&#39;Default value&#39;</span>
    
    <span class="k">def</span> <span class="nf">value_getter</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">_value</span>

    <span class="k">def</span> <span class="nf">value_setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">newvalue</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_value</span> <span class="o">=</span> <span class="n">newvalue</span>

    <span class="n">value</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">value_getter</span><span class="p">,</span> <span class="n">value_setter</span><span class="p">)</span>


<span class="k">try</span><span class="p">:</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">Base</span><span class="p">()</span>
    <span class="k">print</span> <span class="s">&#39;Base.value:&#39;</span><span class="p">,</span> <span class="n">b</span><span class="o">.</span><span class="n">value</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">err</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;ERROR:&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>

<span class="k">try</span><span class="p">:</span>
    <span class="n">p</span> <span class="o">=</span> <span class="n">PartialImplementation</span><span class="p">()</span>
    <span class="k">print</span> <span class="s">&#39;PartialImplementation.value:&#39;</span><span class="p">,</span> <span class="n">p</span><span class="o">.</span><span class="n">value</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">,</span> <span class="n">err</span><span class="p">:</span>
    <span class="k">print</span> <span class="s">&#39;ERROR:&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">err</span><span class="p">)</span>

<span class="n">i</span> <span class="o">=</span> <span class="n">Implementation</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;Implementation.value:&#39;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">value</span>

<span class="n">i</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="s">&#39;New value&#39;</span>
<span class="k">print</span> <span class="s">&#39;Changed value:&#39;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">value</span>
</pre></div>
</div>
<p>Notice that the concrete property must be defined the same way as the
abstract property.  Trying to override a read/write property in
<tt class="docutils literal"><span class="pre">PartialImplementation</span></tt> with one that is read-only does not work.</p>
<div class="highlight-python"><pre>$ python abc_abstractproperty_rw.py

ERROR: Can't instantiate abstract class Base with abstract methods value
ERROR: Can't instantiate abstract class PartialImplementation with abstract methods value
Implementation.value: Default value
Changed value: New value</pre>
</div>
<p>To use the decorator syntax does with read/write abstract properties,
the methods to get and set the value should be named the same.</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">abc</span>

<span class="k">class</span> <span class="nc">Base</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="n">__metaclass__</span> <span class="o">=</span> <span class="n">abc</span><span class="o">.</span><span class="n">ABCMeta</span>
    
    <span class="nd">@abc.abstractproperty</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="s">&#39;Should never see this&#39;</span>
    
    <span class="nd">@value.setter</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">newvalue</span><span class="p">):</span>
        <span class="k">return</span>


<span class="k">class</span> <span class="nc">Implementation</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
    
    <span class="n">_value</span> <span class="o">=</span> <span class="s">&#39;Default value&#39;</span>
    
    <span class="nd">@property</span>
    <span class="k">def</span> <span class="nf">value</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">_value</span>

    <span class="nd">@value.setter</span>
    <span class="k">def</span> <span class="nf">value</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">newvalue</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">_value</span> <span class="o">=</span> <span class="n">newvalue</span>


<span class="n">i</span> <span class="o">=</span> <span class="n">Implementation</span><span class="p">()</span>
<span class="k">print</span> <span class="s">&#39;Implementation.value:&#39;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">value</span>

<span class="n">i</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="s">&#39;New value&#39;</span>
<span class="k">print</span> <span class="s">&#39;Changed value:&#39;</span><span class="p">,</span> <span class="n">i</span><span class="o">.</span><span class="n">value</span>
</pre></div>
</div>
<p>Notice that both methods in the <tt class="docutils literal"><span class="pre">Base</span></tt> and <tt class="docutils literal"><span class="pre">Implementation</span></tt>
classes are named <tt class="docutils literal"><span class="pre">value()</span></tt>, although they have different
signatures.</p>
<div class="highlight-python"><pre>$ python abc_abstractproperty_rw_deco.py

Implementation.value: Default value
Changed value: New value</pre>
</div>
</div>
<div class="section" id="collection-types">
<span id="abc-collection-types"></span><h2>Collection Types<a class="headerlink" href="#collection-types" title="Permalink to this headline">¶</a></h2>
<p>The <a class="reference internal" href="../collections/index.html#module-collections" title="collections: Container data types."><tt class="xref py py-mod docutils literal"><span class="pre">collections</span></tt></a> module defines several abstract base classes
related to container (and containable) types.</p>
<p>General container classes:</p>
<ul class="simple">
<li>Container</li>
<li>Sized</li>
</ul>
<p>Iterator and Sequence classes:</p>
<ul class="simple">
<li>Iterable</li>
<li>Iterator</li>
<li>Sequence</li>
<li>MutableSequence</li>
</ul>
<p>Unique values:</p>
<ul class="simple">
<li>Hashable</li>
<li>Set</li>
<li>MutableSet</li>
</ul>
<p>Mappings:</p>
<ul class="simple">
<li>Mapping</li>
<li>MutableMapping</li>
<li>MappingView</li>
<li>KeysView</li>
<li>ItemsView</li>
<li>ValuesView</li>
</ul>
<p>Miscelaneous:</p>
<ul class="simple">
<li>Callable</li>
</ul>
<p>In addition to serving as detailed real-world examples of abstract
base classes, Python&#8217;s built-in types are automatically registered to
these classes when you import <a class="reference internal" href="../collections/index.html#module-collections" title="collections: Container data types."><tt class="xref py py-mod docutils literal"><span class="pre">collections</span></tt></a>. This means you can
safely use <tt class="docutils literal"><span class="pre">isinstance()</span></tt> to check parameters in your code to ensure
that they support the API you need.  The base classes can also be used
to define your own collection types, since many of them provide
concrete implementations of the internals and only need a few methods
overridden.  Refer to the standard library docs for collections for
more details.</p>
<div class="admonition-see-also admonition seealso">
<p class="first admonition-title">See also</p>
<dl class="last docutils">
<dt><a class="reference external" href="http://docs.python.org/library/abc.html">abc</a></dt>
<dd>The standard library documentation for this module.</dd>
<dt><span class="target" id="index-0"></span><a class="pep reference external" href="http://www.python.org/dev/peps/pep-3119"><strong>PEP 3119</strong></a></dt>
<dd>Introducing Abstract Base Classes</dd>
<dt><a class="reference internal" href="../collections/index.html#module-collections" title="collections: Container data types."><tt class="xref py py-mod docutils literal"><span class="pre">collections</span></tt></a></dt>
<dd>The collections module includes abstract base classes for several collection types.</dd>
<dt><a class="reference external" href="http://docs.python.org/library/collections.html">collections</a></dt>
<dd>The standard library documentation for collections.</dd>
<dt><span class="target" id="index-1"></span><a class="pep reference external" href="http://www.python.org/dev/peps/pep-3141"><strong>PEP 3141</strong></a></dt>
<dd>A Type Hierarchy for Numbers</dd>
<dt><a class="reference external" href="http://en.wikipedia.org/wiki/Strategy_pattern">Wikipedia: Strategy Pattern</a></dt>
<dd>Description and examples of the strategy pattern.</dd>
<dt><a class="reference external" href="http://us.pycon.org/2009/conference/schedule/event/47/">Plugins and monkeypatching</a></dt>
<dd>PyCon 2009 presentation by Dr. André Roberge</dd>
</dl>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="../genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="../py-modindex.html" title="Python Module Index"
             >modules</a> |</li>
        <li class="right" >
          <a href="../atexit/index.html" title="atexit – Call functions when a program is closing down"
             >next</a> |</li>
        <li class="right" >
          <a href="../runtime_services.html" title="Python Runtime Services"
             >previous</a> |</li>
        <li><a href="../contents.html">PyMOTW</a> &raquo;</li>
          <li><a href="../runtime_services.html" >Python Runtime Services</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
      &copy; Copyright Doug Hellmann.
      Last updated on Oct 24, 2010.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>.

    <br/><a href="http://creativecommons.org/licenses/by-nc-sa/3.0/us/" rel="license"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by-nc-sa/3.0/us/88x31.png"/></a>
    
    </div>
  </body>
</html>

[top] / python / PyMOTW / docs / abc / index.html

contact | logmethods.com