Sh3ll
OdayForums


Server : Apache
System : Linux server1.cgrithy.com 3.10.0-1160.95.1.el7.x86_64 #1 SMP Mon Jul 24 13:59:37 UTC 2023 x86_64
User : nobody ( 99)
PHP Version : 8.1.23
Disable Function : NONE
Directory :  /usr/share/doc/python-docs-2.7.5/html/howto/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : //usr/share/doc/python-docs-2.7.5/html/howto/descriptor.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>Descriptor HowTo Guide &mdash; Python 2.7.5 documentation</title>
    
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '2.7.5',
        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>
    <script type="text/javascript" src="../_static/sidebar.js"></script>
    <link rel="search" type="application/opensearchdescription+xml"
          title="Search within Python 2.7.5 documentation"
          href="../_static/opensearch.xml"/>
    <link rel="author" title="About these documents" href="../about.html" />
    <link rel="copyright" title="Copyright" href="../copyright.html" />
    <link rel="top" title="Python 2.7.5 documentation" href="../index.html" />
    <link rel="up" title="Python HOWTOs" href="index.html" />
    <link rel="next" title="Idioms and Anti-Idioms in Python" href="doanddont.html" />
    <link rel="prev" title="Curses Programming with Python" href="curses.html" />
    <link rel="shortcut icon" type="image/png" href="../_static/py.png" />
    <script type="text/javascript" src="../_static/copybutton.js"></script>
    
 

  </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="doanddont.html" title="Idioms and Anti-Idioms in Python"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="curses.html" title="Curses Programming with Python"
             accesskey="P">previous</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="http://www.python.org/">Python</a> &raquo;</li>
        <li>
          <a href="../index.html">Python 2.7.5 documentation</a> &raquo;
        </li>

          <li><a href="index.html" accesskey="U">Python HOWTOs</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="descriptor-howto-guide">
<h1><a class="toc-backref" href="#id1">Descriptor HowTo Guide</a><a class="headerlink" href="#descriptor-howto-guide" 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-odd field"><th class="field-name">Author:</th><td class="field-body">Raymond Hettinger</td>
</tr>
<tr class="field-even field"><th class="field-name">Contact:</th><td class="field-body">&lt;python at rcn dot com&gt;</td>
</tr>
</tbody>
</table>
<div class="contents topic" id="contents">
<p class="topic-title first">Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#descriptor-howto-guide" id="id1">Descriptor HowTo Guide</a><ul>
<li><a class="reference internal" href="#abstract" id="id2">Abstract</a></li>
<li><a class="reference internal" href="#definition-and-introduction" id="id3">Definition and Introduction</a></li>
<li><a class="reference internal" href="#descriptor-protocol" id="id4">Descriptor Protocol</a></li>
<li><a class="reference internal" href="#invoking-descriptors" id="id5">Invoking Descriptors</a></li>
<li><a class="reference internal" href="#descriptor-example" id="id6">Descriptor Example</a></li>
<li><a class="reference internal" href="#properties" id="id7">Properties</a></li>
<li><a class="reference internal" href="#functions-and-methods" id="id8">Functions and Methods</a></li>
<li><a class="reference internal" href="#static-methods-and-class-methods" id="id9">Static Methods and Class Methods</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="abstract">
<h2><a class="toc-backref" href="#id2">Abstract</a><a class="headerlink" href="#abstract" title="Permalink to this headline">¶</a></h2>
<p>Defines descriptors, summarizes the protocol, and shows how descriptors are
called.  Examines a custom descriptor and several built-in python descriptors
including functions, properties, static methods, and class methods.  Shows how
each works by giving a pure Python equivalent and a sample application.</p>
<p>Learning about descriptors not only provides access to a larger toolset, it
creates a deeper understanding of how Python works and an appreciation for the
elegance of its design.</p>
</div>
<div class="section" id="definition-and-introduction">
<h2><a class="toc-backref" href="#id3">Definition and Introduction</a><a class="headerlink" href="#definition-and-introduction" title="Permalink to this headline">¶</a></h2>
<p>In general, a descriptor is an object attribute with &#8220;binding behavior&#8221;, one
whose attribute access has been overridden by methods in the descriptor
protocol.  Those methods are <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a>, <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><tt class="xref py py-meth docutils literal"><span class="pre">__set__()</span></tt></a>, and
<a class="reference internal" href="../reference/datamodel.html#object.__delete__" title="object.__delete__"><tt class="xref py py-meth docutils literal"><span class="pre">__delete__()</span></tt></a>.  If any of those methods are defined for an object, it is
said to be a descriptor.</p>
<p>The default behavior for attribute access is to get, set, or delete the
attribute from an object&#8217;s dictionary.  For instance, <tt class="docutils literal"><span class="pre">a.x</span></tt> has a lookup chain
starting with <tt class="docutils literal"><span class="pre">a.__dict__['x']</span></tt>, then <tt class="docutils literal"><span class="pre">type(a).__dict__['x']</span></tt>, and
continuing through the base classes of <tt class="docutils literal"><span class="pre">type(a)</span></tt> excluding metaclasses. If the
looked-up value is an object defining one of the descriptor methods, then Python
may override the default behavior and invoke the descriptor method instead.
Where this occurs in the precedence chain depends on which descriptor methods
were defined.  Note that descriptors are only invoked for new style objects or
classes (a class is new style if it inherits from <a class="reference internal" href="../library/functions.html#object" title="object"><tt class="xref py py-class docutils literal"><span class="pre">object</span></tt></a> or
<a class="reference internal" href="../library/functions.html#type" title="type"><tt class="xref py py-class docutils literal"><span class="pre">type</span></tt></a>).</p>
<p>Descriptors are a powerful, general purpose protocol.  They are the mechanism
behind properties, methods, static methods, class methods, and <a class="reference internal" href="../library/functions.html#super" title="super"><tt class="xref py py-func docutils literal"><span class="pre">super()</span></tt></a>.
They are used throughout Python itself to implement the new style classes
introduced in version 2.2.  Descriptors simplify the underlying C-code and offer
a flexible set of new tools for everyday Python programs.</p>
</div>
<div class="section" id="descriptor-protocol">
<h2><a class="toc-backref" href="#id4">Descriptor Protocol</a><a class="headerlink" href="#descriptor-protocol" title="Permalink to this headline">¶</a></h2>
<p><tt class="docutils literal"><span class="pre">descr.__get__(self,</span> <span class="pre">obj,</span> <span class="pre">type=None)</span> <span class="pre">--&gt;</span> <span class="pre">value</span></tt></p>
<p><tt class="docutils literal"><span class="pre">descr.__set__(self,</span> <span class="pre">obj,</span> <span class="pre">value)</span> <span class="pre">--&gt;</span> <span class="pre">None</span></tt></p>
<p><tt class="docutils literal"><span class="pre">descr.__delete__(self,</span> <span class="pre">obj)</span> <span class="pre">--&gt;</span> <span class="pre">None</span></tt></p>
<p>That is all there is to it.  Define any of these methods and an object is
considered a descriptor and can override default behavior upon being looked up
as an attribute.</p>
<p>If an object defines both <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> and <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><tt class="xref py py-meth docutils literal"><span class="pre">__set__()</span></tt></a>, it is considered
a data descriptor.  Descriptors that only define <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> are called
non-data descriptors (they are typically used for methods but other uses are
possible).</p>
<p>Data and non-data descriptors differ in how overrides are calculated with
respect to entries in an instance&#8217;s dictionary.  If an instance&#8217;s dictionary
has an entry with the same name as a data descriptor, the data descriptor
takes precedence.  If an instance&#8217;s dictionary has an entry with the same
name as a non-data descriptor, the dictionary entry takes precedence.</p>
<p>To make a read-only data descriptor, define both <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> and
<a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><tt class="xref py py-meth docutils literal"><span class="pre">__set__()</span></tt></a> with the <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><tt class="xref py py-meth docutils literal"><span class="pre">__set__()</span></tt></a> raising an <a class="reference internal" href="../library/exceptions.html#exceptions.AttributeError" title="exceptions.AttributeError"><tt class="xref py py-exc docutils literal"><span class="pre">AttributeError</span></tt></a> when
called.  Defining the <a class="reference internal" href="../reference/datamodel.html#object.__set__" title="object.__set__"><tt class="xref py py-meth docutils literal"><span class="pre">__set__()</span></tt></a> method with an exception raising
placeholder is enough to make it a data descriptor.</p>
</div>
<div class="section" id="invoking-descriptors">
<h2><a class="toc-backref" href="#id5">Invoking Descriptors</a><a class="headerlink" href="#invoking-descriptors" title="Permalink to this headline">¶</a></h2>
<p>A descriptor can be called directly by its method name.  For example,
<tt class="docutils literal"><span class="pre">d.__get__(obj)</span></tt>.</p>
<p>Alternatively, it is more common for a descriptor to be invoked automatically
upon attribute access.  For example, <tt class="docutils literal"><span class="pre">obj.d</span></tt> looks up <tt class="docutils literal"><span class="pre">d</span></tt> in the dictionary
of <tt class="docutils literal"><span class="pre">obj</span></tt>.  If <tt class="docutils literal"><span class="pre">d</span></tt> defines the method <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a>, then <tt class="docutils literal"><span class="pre">d.__get__(obj)</span></tt>
is invoked according to the precedence rules listed below.</p>
<p>The details of invocation depend on whether <tt class="docutils literal"><span class="pre">obj</span></tt> is an object or a class.
Either way, descriptors only work for new style objects and classes.  A class is
new style if it is a subclass of <a class="reference internal" href="../library/functions.html#object" title="object"><tt class="xref py py-class docutils literal"><span class="pre">object</span></tt></a>.</p>
<p>For objects, the machinery is in <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">object.__getattribute__()</span></tt></a> which
transforms <tt class="docutils literal"><span class="pre">b.x</span></tt> into <tt class="docutils literal"><span class="pre">type(b).__dict__['x'].__get__(b,</span> <span class="pre">type(b))</span></tt>.  The
implementation works through a precedence chain that gives data descriptors
priority over instance variables, instance variables priority over non-data
descriptors, and assigns lowest priority to <a class="reference internal" href="../reference/datamodel.html#object.__getattr__" title="object.__getattr__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattr__()</span></tt></a> if provided.  The
full C implementation can be found in <a class="reference internal" href="../c-api/object.html#PyObject_GenericGetAttr" title="PyObject_GenericGetAttr"><tt class="xref c c-func docutils literal"><span class="pre">PyObject_GenericGetAttr()</span></tt></a> in
<a class="reference external" href="http://svn.python.org/view/python/trunk/Objects/object.c?view=markup">Objects/object.c</a>.</p>
<p>For classes, the machinery is in <tt class="xref py py-meth docutils literal"><span class="pre">type.__getattribute__()</span></tt> which transforms
<tt class="docutils literal"><span class="pre">B.x</span></tt> into <tt class="docutils literal"><span class="pre">B.__dict__['x'].__get__(None,</span> <span class="pre">B)</span></tt>.  In pure Python, it looks
like:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span>
    <span class="s">&quot;Emulate type_getattro() in Objects/typeobject.c&quot;</span>
    <span class="n">v</span> <span class="o">=</span> <span class="nb">object</span><span class="o">.</span><span class="n">__getattribute__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span>
    <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="s">&#39;__get__&#39;</span><span class="p">):</span>
       <span class="k">return</span> <span class="n">v</span><span class="o">.</span><span class="n">__get__</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">v</span>
</pre></div>
</div>
<p>The important points to remember are:</p>
<ul class="simple">
<li>descriptors are invoked by the <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a> method</li>
<li>overriding <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a> prevents automatic descriptor calls</li>
<li><a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a> is only available with new style classes and objects</li>
<li><a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">object.__getattribute__()</span></tt></a> and <tt class="xref py py-meth docutils literal"><span class="pre">type.__getattribute__()</span></tt> make
different calls to <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a>.</li>
<li>data descriptors always override instance dictionaries.</li>
<li>non-data descriptors may be overridden by instance dictionaries.</li>
</ul>
<p>The object returned by <tt class="docutils literal"><span class="pre">super()</span></tt> also has a custom <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a>
method for invoking descriptors.  The call <tt class="docutils literal"><span class="pre">super(B,</span> <span class="pre">obj).m()</span></tt> searches
<tt class="docutils literal"><span class="pre">obj.__class__.__mro__</span></tt> for the base class <tt class="docutils literal"><span class="pre">A</span></tt> immediately following <tt class="docutils literal"><span class="pre">B</span></tt>
and then returns <tt class="docutils literal"><span class="pre">A.__dict__['m'].__get__(obj,</span> <span class="pre">A)</span></tt>.  If not a descriptor,
<tt class="docutils literal"><span class="pre">m</span></tt> is returned unchanged.  If not in the dictionary, <tt class="docutils literal"><span class="pre">m</span></tt> reverts to a
search using <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">object.__getattribute__()</span></tt></a>.</p>
<p>Note, in Python 2.2, <tt class="docutils literal"><span class="pre">super(B,</span> <span class="pre">obj).m()</span></tt> would only invoke <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> if
<tt class="docutils literal"><span class="pre">m</span></tt> was a data descriptor.  In Python 2.3, non-data descriptors also get
invoked unless an old-style class is involved.  The implementation details are
in <tt class="xref c c-func docutils literal"><span class="pre">super_getattro()</span></tt> in
<a class="reference external" href="http://svn.python.org/view/python/trunk/Objects/typeobject.c?view=markup">Objects/typeobject.c</a>
and a pure Python equivalent can be found in <a class="reference external" href="http://www.python.org/2.2.3/descrintro.html#cooperation">Guido&#8217;s Tutorial</a>.</p>
<p>The details above show that the mechanism for descriptors is embedded in the
<a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a> methods for <a class="reference internal" href="../library/functions.html#object" title="object"><tt class="xref py py-class docutils literal"><span class="pre">object</span></tt></a>, <a class="reference internal" href="../library/functions.html#type" title="type"><tt class="xref py py-class docutils literal"><span class="pre">type</span></tt></a>, and
<a class="reference internal" href="../library/functions.html#super" title="super"><tt class="xref py py-func docutils literal"><span class="pre">super()</span></tt></a>.  Classes inherit this machinery when they derive from
<a class="reference internal" href="../library/functions.html#object" title="object"><tt class="xref py py-class docutils literal"><span class="pre">object</span></tt></a> or if they have a meta-class providing similar functionality.
Likewise, classes can turn-off descriptor invocation by overriding
<a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a>.</p>
</div>
<div class="section" id="descriptor-example">
<h2><a class="toc-backref" href="#id6">Descriptor Example</a><a class="headerlink" href="#descriptor-example" title="Permalink to this headline">¶</a></h2>
<p>The following code creates a class whose objects are data descriptors which
print a message for each get or set.  Overriding <a class="reference internal" href="../reference/datamodel.html#object.__getattribute__" title="object.__getattribute__"><tt class="xref py py-meth docutils literal"><span class="pre">__getattribute__()</span></tt></a> is
alternate approach that could do this for every attribute.  However, this
descriptor is useful for monitoring just a few chosen attributes:</p>
<div class="highlight-python"><pre>class RevealAccess(object):
    """A data descriptor that sets and returns values
       normally and prints a message logging their access.
    """

    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print 'Retrieving', self.name
        return self.val

    def __set__(self, obj, val):
        print 'Updating' , self.name
        self.val = val

&gt;&gt;&gt; class MyClass(object):
    x = RevealAccess(10, 'var "x"')
    y = 5

&gt;&gt;&gt; m = MyClass()
&gt;&gt;&gt; m.x
Retrieving var "x"
10
&gt;&gt;&gt; m.x = 20
Updating var "x"
&gt;&gt;&gt; m.x
Retrieving var "x"
20
&gt;&gt;&gt; m.y
5</pre>
</div>
<p>The protocol is simple and offers exciting possibilities.  Several use cases are
so common that they have been packaged into individual function calls.
Properties, bound and unbound methods, static methods, and class methods are all
based on the descriptor protocol.</p>
</div>
<div class="section" id="properties">
<h2><a class="toc-backref" href="#id7">Properties</a><a class="headerlink" href="#properties" title="Permalink to this headline">¶</a></h2>
<p>Calling <a class="reference internal" href="../library/functions.html#property" title="property"><tt class="xref py py-func docutils literal"><span class="pre">property()</span></tt></a> is a succinct way of building a data descriptor that
triggers function calls upon access to an attribute.  Its signature is:</p>
<div class="highlight-python"><pre>property(fget=None, fset=None, fdel=None, doc=None) -&gt; property attribute</pre>
</div>
<p>The documentation shows a typical use to define a managed attribute <tt class="docutils literal"><span class="pre">x</span></tt>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">C</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">getx</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">__x</span>
    <span class="k">def</span> <span class="nf">setx</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span> <span class="o">=</span> <span class="n">value</span>
    <span class="k">def</span> <span class="nf">delx</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">__x</span>
    <span class="n">x</span> <span class="o">=</span> <span class="nb">property</span><span class="p">(</span><span class="n">getx</span><span class="p">,</span> <span class="n">setx</span><span class="p">,</span> <span class="n">delx</span><span class="p">,</span> <span class="s">&quot;I&#39;m the &#39;x&#39; property.&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>To see how <a class="reference internal" href="../library/functions.html#property" title="property"><tt class="xref py py-func docutils literal"><span class="pre">property()</span></tt></a> is implemented in terms of the descriptor protocol,
here is a pure Python equivalent:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Property</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="s">&quot;Emulate PyProperty_Type() in Objects/descrobject.c&quot;</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fget</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">fset</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">fdel</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">doc</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="o">=</span> <span class="n">fget</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="o">=</span> <span class="n">fset</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="o">=</span> <span class="n">fdel</span>
        <span class="k">if</span> <span class="n">doc</span> <span class="ow">is</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">fget</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">doc</span> <span class="o">=</span> <span class="n">fget</span><span class="o">.</span><span class="n">__doc__</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">__doc__</span> <span class="o">=</span> <span class="n">doc</span>

    <span class="k">def</span> <span class="nf">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">self</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s">&quot;unreadable attribute&quot;</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">fget</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__set__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fset</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s">&quot;can&#39;t set attribute&quot;</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="n">obj</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">__delete__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="s">&quot;can&#39;t delete attribute&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">fdel</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">getter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fget</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)(</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> <span class="bp">self</span><span class="o">.</span><span class="n">__doc__</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">setter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fset</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</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="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> <span class="bp">self</span><span class="o">.</span><span class="n">__doc__</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">deleter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fdel</span><span class="p">):</span>
        <span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</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="n">fdel</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__doc__</span><span class="p">)</span>
</pre></div>
</div>
<p>The <a class="reference internal" href="../library/functions.html#property" title="property"><tt class="xref py py-func docutils literal"><span class="pre">property()</span></tt></a> builtin helps whenever a user interface has granted
attribute access and then subsequent changes require the intervention of a
method.</p>
<p>For instance, a spreadsheet class may grant access to a cell value through
<tt class="docutils literal"><span class="pre">Cell('b10').value</span></tt>. Subsequent improvements to the program require the cell
to be recalculated on every access; however, the programmer does not want to
affect existing client code accessing the attribute directly.  The solution is
to wrap access to the value attribute in a property data descriptor:</p>
<div class="highlight-python"><pre>class Cell(object):
    . . .
    def getvalue(self, obj):
        "Recalculate cell before returning value"
        self.recalc()
        return obj._value
    value = property(getvalue)</pre>
</div>
</div>
<div class="section" id="functions-and-methods">
<h2><a class="toc-backref" href="#id8">Functions and Methods</a><a class="headerlink" href="#functions-and-methods" title="Permalink to this headline">¶</a></h2>
<p>Python&#8217;s object oriented features are built upon a function based environment.
Using non-data descriptors, the two are merged seamlessly.</p>
<p>Class dictionaries store methods as functions.  In a class definition, methods
are written using <a class="reference internal" href="../reference/compound_stmts.html#def"><tt class="xref std std-keyword docutils literal"><span class="pre">def</span></tt></a> and <a class="reference internal" href="../reference/expressions.html#lambda"><tt class="xref std std-keyword docutils literal"><span class="pre">lambda</span></tt></a>, the usual tools for
creating functions.  The only difference from regular functions is that the
first argument is reserved for the object instance.  By Python convention, the
instance reference is called <em>self</em> but may be called <em>this</em> or any other
variable name.</p>
<p>To support method calls, functions include the <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> method for
binding methods during attribute access.  This means that all functions are
non-data descriptors which return bound or unbound methods depending whether
they are invoked from an object or a class.  In pure python, it works like
this:</p>
<div class="highlight-python"><pre>class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj, objtype)</pre>
</div>
<p>Running the interpreter shows how the function descriptor works in practice:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">D</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="go">     def f(self, x):</span>
<span class="go">          return x</span>

<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span> <span class="o">=</span> <span class="n">D</span><span class="p">()</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">D</span><span class="o">.</span><span class="n">__dict__</span><span class="p">[</span><span class="s">&#39;f&#39;</span><span class="p">]</span> <span class="c"># Stored internally as a function</span>
<span class="go">&lt;function f at 0x00C45070&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">D</span><span class="o">.</span><span class="n">f</span>             <span class="c"># Get from a class becomes an unbound method</span>
<span class="go">&lt;unbound method D.f&gt;</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">d</span><span class="o">.</span><span class="n">f</span>             <span class="c"># Get from an instance becomes a bound method</span>
<span class="go">&lt;bound method D.f of &lt;__main__.D object at 0x00B18C90&gt;&gt;</span>
</pre></div>
</div>
<p>The output suggests that bound and unbound methods are two different types.
While they could have been implemented that way, the actual C implementation of
<a class="reference internal" href="../c-api/method.html#PyMethod_Type" title="PyMethod_Type"><tt class="xref c c-type docutils literal"><span class="pre">PyMethod_Type</span></tt></a> in
<a class="reference external" href="http://svn.python.org/view/python/trunk/Objects/classobject.c?view=markup">Objects/classobject.c</a>
is a single object with two different representations depending on whether the
<tt class="xref py py-attr docutils literal"><span class="pre">im_self</span></tt> field is set or is <em>NULL</em> (the C equivalent of <em>None</em>).</p>
<p>Likewise, the effects of calling a method object depend on the <tt class="xref py py-attr docutils literal"><span class="pre">im_self</span></tt>
field. If set (meaning bound), the original function (stored in the
<tt class="xref py py-attr docutils literal"><span class="pre">im_func</span></tt> field) is called as expected with the first argument set to the
instance.  If unbound, all of the arguments are passed unchanged to the original
function. The actual C implementation of <tt class="xref py py-func docutils literal"><span class="pre">instancemethod_call()</span></tt> is only
slightly more complex in that it includes some type checking.</p>
</div>
<div class="section" id="static-methods-and-class-methods">
<h2><a class="toc-backref" href="#id9">Static Methods and Class Methods</a><a class="headerlink" href="#static-methods-and-class-methods" title="Permalink to this headline">¶</a></h2>
<p>Non-data descriptors provide a simple mechanism for variations on the usual
patterns of binding functions into methods.</p>
<p>To recap, functions have a <a class="reference internal" href="../reference/datamodel.html#object.__get__" title="object.__get__"><tt class="xref py py-meth docutils literal"><span class="pre">__get__()</span></tt></a> method so that they can be converted
to a method when accessed as attributes.  The non-data descriptor transforms a
<tt class="docutils literal"><span class="pre">obj.f(*args)</span></tt> call into <tt class="docutils literal"><span class="pre">f(obj,</span> <span class="pre">*args)</span></tt>.  Calling <tt class="docutils literal"><span class="pre">klass.f(*args)</span></tt>
becomes <tt class="docutils literal"><span class="pre">f(*args)</span></tt>.</p>
<p>This chart summarizes the binding and its two most useful variants:</p>
<blockquote>
<div><table border="1" class="docutils">
<colgroup>
<col width="30%" />
<col width="39%" />
<col width="32%" />
</colgroup>
<thead valign="bottom">
<tr class="row-odd"><th class="head">Transformation</th>
<th class="head">Called from an
Object</th>
<th class="head">Called from a
Class</th>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td>function</td>
<td>f(obj, *args)</td>
<td>f(*args)</td>
</tr>
<tr class="row-odd"><td>staticmethod</td>
<td>f(*args)</td>
<td>f(*args)</td>
</tr>
<tr class="row-even"><td>classmethod</td>
<td>f(type(obj), *args)</td>
<td>f(klass, *args)</td>
</tr>
</tbody>
</table>
</div></blockquote>
<p>Static methods return the underlying function without changes.  Calling either
<tt class="docutils literal"><span class="pre">c.f</span></tt> or <tt class="docutils literal"><span class="pre">C.f</span></tt> is the equivalent of a direct lookup into
<tt class="docutils literal"><span class="pre">object.__getattribute__(c,</span> <span class="pre">&quot;f&quot;)</span></tt> or <tt class="docutils literal"><span class="pre">object.__getattribute__(C,</span> <span class="pre">&quot;f&quot;)</span></tt>. As a
result, the function becomes identically accessible from either an object or a
class.</p>
<p>Good candidates for static methods are methods that do not reference the
<tt class="docutils literal"><span class="pre">self</span></tt> variable.</p>
<p>For instance, a statistics package may include a container class for
experimental data.  The class provides normal methods for computing the average,
mean, median, and other descriptive statistics that depend on the data. However,
there may be useful functions which are conceptually related but do not depend
on the data.  For instance, <tt class="docutils literal"><span class="pre">erf(x)</span></tt> is handy conversion routine that comes up
in statistical work but does not directly depend on a particular dataset.
It can be called either from an object or the class:  <tt class="docutils literal"><span class="pre">s.erf(1.5)</span> <span class="pre">--&gt;</span> <span class="pre">.9332</span></tt> or
<tt class="docutils literal"><span class="pre">Sample.erf(1.5)</span> <span class="pre">--&gt;</span> <span class="pre">.9332</span></tt>.</p>
<p>Since staticmethods return the underlying function with no changes, the example
calls are unexciting:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">E</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="go">     def f(x):</span>
<span class="go">          print x</span>
<span class="go">     f = staticmethod(f)</span>

<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">E</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="go">3</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">E</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="go">3</span>
</pre></div>
</div>
<p>Using the non-data descriptor protocol, a pure Python version of
<a class="reference internal" href="../library/functions.html#staticmethod" title="staticmethod"><tt class="xref py py-func docutils literal"><span class="pre">staticmethod()</span></tt></a> would look like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">StaticMethod</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
 <span class="s">&quot;Emulate PyStaticMethod_Type() in Objects/funcobject.c&quot;</span>

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

 <span class="k">def</span> <span class="nf">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">objtype</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
      <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span>
</pre></div>
</div>
<p>Unlike static methods, class methods prepend the class reference to the
argument list before calling the function.  This format is the same
for whether the caller is an object or a class:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">E</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="go">     def f(klass, x):</span>
<span class="go">          return klass.__name__, x</span>
<span class="go">     f = classmethod(f)</span>

<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">E</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="go">(&#39;E&#39;, 3)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">print</span> <span class="n">E</span><span class="p">()</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="go">(&#39;E&#39;, 3)</span>
</pre></div>
</div>
<p>This behavior is useful whenever the function only needs to have a class
reference and does not care about any underlying data.  One use for classmethods
is to create alternate class constructors.  In Python 2.3, the classmethod
<a class="reference internal" href="../library/stdtypes.html#dict.fromkeys" title="dict.fromkeys"><tt class="xref py py-func docutils literal"><span class="pre">dict.fromkeys()</span></tt></a> creates a new dictionary from a list of keys.  The pure
Python equivalent is:</p>
<div class="highlight-python"><pre>class Dict(object):
    . . .
    def fromkeys(klass, iterable, value=None):
        "Emulate dict_fromkeys() in Objects/dictobject.c"
        d = klass()
        for key in iterable:
            d[key] = value
        return d
    fromkeys = classmethod(fromkeys)</pre>
</div>
<p>Now a new dictionary of unique keys can be constructed like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="n">Dict</span><span class="o">.</span><span class="n">fromkeys</span><span class="p">(</span><span class="s">&#39;abracadabra&#39;</span><span class="p">)</span>
<span class="go">{&#39;a&#39;: None, &#39;r&#39;: None, &#39;b&#39;: None, &#39;c&#39;: None, &#39;d&#39;: None}</span>
</pre></div>
</div>
<p>Using the non-data descriptor protocol, a pure Python version of
<a class="reference internal" href="../library/functions.html#classmethod" title="classmethod"><tt class="xref py py-func docutils literal"><span class="pre">classmethod()</span></tt></a> would look like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">ClassMethod</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
     <span class="s">&quot;Emulate PyClassMethod_Type() in Objects/funcobject.c&quot;</span>

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

     <span class="k">def</span> <span class="nf">__get__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="n">klass</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
          <span class="k">if</span> <span class="n">klass</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
               <span class="n">klass</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
          <span class="k">def</span> <span class="nf">newfunc</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">):</span>
               <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">f</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>
          <span class="k">return</span> <span class="n">newfunc</span>
</pre></div>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../contents.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Descriptor HowTo Guide</a><ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#definition-and-introduction">Definition and Introduction</a></li>
<li><a class="reference internal" href="#descriptor-protocol">Descriptor Protocol</a></li>
<li><a class="reference internal" href="#invoking-descriptors">Invoking Descriptors</a></li>
<li><a class="reference internal" href="#descriptor-example">Descriptor Example</a></li>
<li><a class="reference internal" href="#properties">Properties</a></li>
<li><a class="reference internal" href="#functions-and-methods">Functions and Methods</a></li>
<li><a class="reference internal" href="#static-methods-and-class-methods">Static Methods and Class Methods</a></li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="curses.html"
                        title="previous chapter">Curses Programming with Python</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="doanddont.html"
                        title="next chapter">Idioms and Anti-Idioms in Python</a></p>
<h3>This Page</h3>
<ul class="this-page-menu">
  <li><a href="../bugs.html">Report a Bug</a></li>
  <li><a href="../_sources/howto/descriptor.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" />
      <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="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="doanddont.html" title="Idioms and Anti-Idioms in Python"
             >next</a> |</li>
        <li class="right" >
          <a href="curses.html" title="Curses Programming with Python"
             >previous</a> |</li>
        <li><img src="../_static/py.png" alt=""
                 style="vertical-align: middle; margin-top: -1px"/></li>
        <li><a href="http://www.python.org/">Python</a> &raquo;</li>
        <li>
          <a href="../index.html">Python 2.7.5 documentation</a> &raquo;
        </li>

          <li><a href="index.html" >Python HOWTOs</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
    &copy; <a href="../copyright.html">Copyright</a> 1990-2020, Python Software Foundation.
    <br />
    The Python Software Foundation is a non-profit corporation.
    <a href="http://www.python.org/psf/donations/">Please donate.</a>
    <br />
    Last updated on Oct 13, 2020.
    <a href="../bugs.html">Found a bug</a>?
    <br />
    Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
    </div>

  </body>
</html>

ZeroDay Forums Mini