![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /proc/1544360/cwd/usr/share/doc/python3-docs/html/extending/ |
<!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="X-UA-Compatible" content="IE=Edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>2. Defining Extension Types: Tutorial — Python 3.6.7 documentation</title> <link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></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 3.6.7 documentation" href="../_static/opensearch.xml"/> <link rel="author" title="About these documents" href="../about.html" /> <link rel="index" title="Index" href="../genindex.html" /> <link rel="search" title="Search" href="../search.html" /> <link rel="copyright" title="Copyright" href="../copyright.html" /> <link rel="next" title="3. Defining Extension Types: Assorted Topics" href="newtypes.html" /> <link rel="prev" title="1. Extending Python with C or C++" href="extending.html" /> <link rel="shortcut icon" type="image/png" href="../_static/py.png" /> <link rel="canonical" href="https://docs.python.org/3/extending/newtypes_tutorial.html" /> <script type="text/javascript" src="../_static/copybutton.js"></script> </head><body> <div class="related" role="navigation" aria-label="related navigation"> <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="newtypes.html" title="3. Defining Extension Types: Assorted Topics" accesskey="N">next</a> |</li> <li class="right" > <a href="extending.html" title="1. Extending Python with C or C++" accesskey="P">previous</a> |</li> <li><img src="../_static/py.png" alt="" style="vertical-align: middle; margin-top: -1px"/></li> <li><a href="https://www.python.org/">Python</a> »</li> <li> <a href="../index.html">3.6.7 Documentation</a> » </li> <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Extending and Embedding the Python Interpreter</a> »</li> <li class="right"> <div class="inline-search" style="display: none" role="search"> <form class="inline-search" action="../search.html" method="get"> <input placeholder="Quick search" 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> </div> <script type="text/javascript">$('.inline-search').show(0);</script> | </li> </ul> </div> <div class="document"> <div class="documentwrapper"> <div class="bodywrapper"> <div class="body" role="main"> <div class="section" id="defining-extension-types-tutorial"> <span id="defining-new-types"></span><h1>2. Defining Extension Types: Tutorial<a class="headerlink" href="#defining-extension-types-tutorial" title="Permalink to this headline">¶</a></h1> <p>Python allows the writer of a C extension module to define new types that can be manipulated from Python code, much like the built-in <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> and <a class="reference internal" href="../library/stdtypes.html#list" title="list"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> types. The code for all extension types follows a pattern, but there are some details that you need to understand before you can get started. This document is a gentle introduction to the topic.</p> <div class="section" id="the-basics"> <span id="dnt-basics"></span><h2>2.1. The Basics<a class="headerlink" href="#the-basics" title="Permalink to this headline">¶</a></h2> <p>The <a class="reference internal" href="../glossary.html#term-cpython"><span class="xref std std-term">CPython</span></a> runtime sees all Python objects as variables of type <a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject*</span></code></a>, which serves as a “base type” for all Python objects. The <a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject</span></code></a> structure itself only contains the object’s <a class="reference internal" href="../glossary.html#term-reference-count"><span class="xref std std-term">reference count</span></a> and a pointer to the object’s “type object”. This is where the action is; the type object determines which (C) functions get called by the interpreter when, for instance, an attribute gets looked up on an object, a method called, or it is multiplied by another object. These C functions are called “type methods”.</p> <p>So, if you want to define a new extension type, you need to create a new type object.</p> <p>This sort of thing can only be explained by example, so here’s a minimal, but complete, module that defines a new type named <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> inside a C extension module <code class="xref py py-mod docutils literal notranslate"><span class="pre">custom</span></code>:</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">What we’re showing here is the traditional way of defining <em>static</em> extension types. It should be adequate for most uses. The C API also allows defining heap-allocated extension types using the <a class="reference internal" href="../c-api/type.html#c.PyType_FromSpec" title="PyType_FromSpec"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_FromSpec()</span></code></a> function, which isn’t covered in this tutorial.</p> </div> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="cm">/* Type-specific fields go here. */</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> <span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">CustomType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom.Custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">PyType_GenericNew</span><span class="p">,</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyModuleDef</span> <span class="n">custommodule</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span> <span class="p">.</span><span class="n">m_name</span> <span class="o">=</span> <span class="s">"custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">m_doc</span> <span class="o">=</span> <span class="s">"Example module that creates an extension type."</span><span class="p">,</span> <span class="p">.</span><span class="n">m_size</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">};</span> <span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_custom</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">m</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">custommodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"Custom"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>Now that’s quite a bit to take in at once, but hopefully bits will seem familiar from the previous chapter. This file defines three things:</p> <ol class="arabic simple"> <li>What a <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> <strong>object</strong> contains: this is the <code class="docutils literal notranslate"><span class="pre">CustomObject</span></code> struct, which is allocated once for each <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> instance.</li> <li>How the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> <strong>type</strong> behaves: this is the <code class="docutils literal notranslate"><span class="pre">CustomType</span></code> struct, which defines a set of flags and function pointers that the interpreter inspects when specific operations are requested.</li> <li>How to initialize the <code class="xref py py-mod docutils literal notranslate"><span class="pre">custom</span></code> module: this is the <code class="docutils literal notranslate"><span class="pre">PyInit_custom</span></code> function and the associated <code class="docutils literal notranslate"><span class="pre">custommodule</span></code> struct.</li> </ol> <p>The first bit is:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> </pre></div> </div> <p>This is what a Custom object will contain. <code class="docutils literal notranslate"><span class="pre">PyObject_HEAD</span></code> is mandatory at the start of each object struct and defines a field called <code class="docutils literal notranslate"><span class="pre">ob_base</span></code> of type <a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyObject</span></code></a>, containing a pointer to a type object and a reference count (these can be accessed using the macros <a class="reference internal" href="../c-api/structures.html#c.Py_REFCNT" title="Py_REFCNT"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_REFCNT</span></code></a> and <a class="reference internal" href="../c-api/structures.html#c.Py_TYPE" title="Py_TYPE"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TYPE</span></code></a> respectively). The reason for the macro is to abstract away the layout and to enable additional fields in debug builds.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">There is no semicolon above after the <a class="reference internal" href="../c-api/structures.html#c.PyObject_HEAD" title="PyObject_HEAD"><code class="xref c c-macro docutils literal notranslate"><span class="pre">PyObject_HEAD</span></code></a> macro. Be wary of adding one by accident: some compilers will complain.</p> </div> <p>Of course, objects generally store additional data besides the standard <code class="docutils literal notranslate"><span class="pre">PyObject_HEAD</span></code> boilerplate; for example, here is the definition for standard Python floats:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="kt">double</span> <span class="n">ob_fval</span><span class="p">;</span> <span class="p">}</span> <span class="n">PyFloatObject</span><span class="p">;</span> </pre></div> </div> <p>The second bit is the definition of the type object.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">CustomType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom.Custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">PyType_GenericNew</span><span class="p">,</span> <span class="p">};</span> </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">We recommend using C99-style designated initializers as above, to avoid listing all the <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> fields that you don’t care about and also to avoid caring about the fields’ declaration order.</p> </div> <p>The actual definition of <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> in <code class="file docutils literal notranslate"><span class="pre">object.h</span></code> has many more <a class="reference internal" href="../c-api/typeobj.html#type-structs"><span class="std std-ref">fields</span></a> than the definition above. The remaining fields will be filled with zeros by the C compiler, and it’s common practice to not specify them explicitly unless you need them.</p> <p>We’re going to pick it apart, one field at a time:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> </pre></div> </div> <p>This line is mandatory boilerplate to initialize the <code class="docutils literal notranslate"><span class="pre">ob_base</span></code> field mentioned above.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom.Custom"</span><span class="p">,</span> </pre></div> </div> <p>The name of our type. This will appear in the default textual representation of our objects and in some error messages, for example:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="s2">""</span> <span class="o">+</span> <span class="n">custom</span><span class="o">.</span><span class="n">Custom</span><span class="p">()</span> <span class="gt">Traceback (most recent call last):</span> File <span class="nb">"<stdin>"</span>, line <span class="m">1</span>, in <span class="n"><module></span> <span class="gr">TypeError</span>: <span class="n">can only concatenate str (not "custom.Custom") to str</span> </pre></div> </div> <p>Note that the name is a dotted name that includes both the module name and the name of the type within the module. The module in this case is <code class="xref py py-mod docutils literal notranslate"><span class="pre">custom</span></code> and the type is <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code>, so we set the type name to <code class="xref py py-class docutils literal notranslate"><span class="pre">custom.Custom</span></code>. Using the real dotted import path is important to make your type compatible with the <a class="reference internal" href="../library/pydoc.html#module-pydoc" title="pydoc: Documentation generator and online help system."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pydoc</span></code></a> and <a class="reference internal" href="../library/pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> modules.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> </pre></div> </div> <p>This is so that Python knows how much memory to allocate when creating new <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> instances. <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_itemsize" title="PyTypeObject.tp_itemsize"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_itemsize</span></code></a> is only used for variable-sized objects and should otherwise be zero.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">If you want your type to be subclassable from Python, and your type has the same <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_basicsize" title="PyTypeObject.tp_basicsize"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_basicsize</span></code></a> as its base type, you may have problems with multiple inheritance. A Python subclass of your type will have to list your type first in its <a class="reference internal" href="../library/stdtypes.html#class.__bases__" title="class.__bases__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__bases__</span></code></a>, or else it will not be able to call your type’s <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> method without getting an error. You can avoid this problem by ensuring that your type has a larger value for <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_basicsize" title="PyTypeObject.tp_basicsize"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_basicsize</span></code></a> than its base type does. Most of the time, this will be true anyway, because either your base type will be <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a>, or else you will be adding data members to your base type, and therefore increasing its size.</p> </div> <p>We set the class flags to <a class="reference internal" href="../c-api/typeobj.html#Py_TPFLAGS_DEFAULT" title="Py_TPFLAGS_DEFAULT"><code class="xref py py-const docutils literal notranslate"><span class="pre">Py_TPFLAGS_DEFAULT</span></code></a>.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span><span class="p">,</span> </pre></div> </div> <p>All types should include this constant in their flags. It enables all of the members defined until at least Python 3.3. If you need further members, you will need to OR the corresponding flags.</p> <p>We provide a doc string for the type in <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_doc" title="PyTypeObject.tp_doc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_doc</span></code></a>.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> </pre></div> </div> <p>To enable object creation, we have to provide a <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> handler. This is the equivalent of the Python method <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a>, but has to be specified explicitly. In this case, we can just use the default implementation provided by the API function <a class="reference internal" href="../c-api/type.html#c.PyType_GenericNew" title="PyType_GenericNew"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GenericNew()</span></code></a>.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">PyType_GenericNew</span><span class="p">,</span> </pre></div> </div> <p>Everything else in the file should be familiar, except for some code in <code class="xref c c-func docutils literal notranslate"><span class="pre">PyInit_custom()</span></code>:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span> </pre></div> </div> <p>This initializes the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> type, filling in a number of members to the appropriate default values, including <code class="xref py py-attr docutils literal notranslate"><span class="pre">ob_type</span></code> that we initially set to <em>NULL</em>.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"Custom"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> </pre></div> </div> <p>This adds the type to the module dictionary. This allows us to create <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> instances by calling the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> class:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">custom</span> <span class="gp">>>> </span><span class="n">mycustom</span> <span class="o">=</span> <span class="n">custom</span><span class="o">.</span><span class="n">Custom</span><span class="p">()</span> </pre></div> </div> <p>That’s it! All that remains is to build it; put the above code in a file called <code class="file docutils literal notranslate"><span class="pre">custom.c</span></code> and:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span> <span class="n">setup</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"custom"</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0"</span><span class="p">,</span> <span class="n">ext_modules</span><span class="o">=</span><span class="p">[</span><span class="n">Extension</span><span class="p">(</span><span class="s2">"custom"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"custom.c"</span><span class="p">])])</span> </pre></div> </div> <p>in a file called <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code>; then typing</p> <div class="highlight-shell-session notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> python setup.py build </pre></div> </div> <p>at a shell should produce a file <code class="file docutils literal notranslate"><span class="pre">custom.so</span></code> in a subdirectory; move to that directory and fire up Python — you should be able to <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">custom</span></code> and play around with Custom objects.</p> <p>That wasn’t so hard, was it?</p> <p>Of course, the current Custom type is pretty uninteresting. It has no data and doesn’t do anything. It can’t even be subclassed.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">While this documentation showcases the standard <a class="reference internal" href="../library/distutils.html#module-distutils" title="distutils: Support for building and installing Python modules into an existing Python installation."><code class="xref py py-mod docutils literal notranslate"><span class="pre">distutils</span></code></a> module for building C extensions, it is recommended in real-world use cases to use the newer and better-maintained <code class="docutils literal notranslate"><span class="pre">setuptools</span></code> library. Documentation on how to do this is out of scope for this document and can be found in the <a class="reference external" href="https://packaging.python.org/tutorials/distributing-packages/">Python Packaging User’s Guide</a>.</p> </div> </div> <div class="section" id="adding-data-and-methods-to-the-basic-example"> <h2>2.2. Adding data and methods to the Basic example<a class="headerlink" href="#adding-data-and-methods-to-the-basic-example" title="Permalink to this headline">¶</a></h2> <p>Let’s extend the basic example to add some data and methods. Let’s also make the type usable as a base class. We’ll create a new module, <code class="xref py py-mod docutils literal notranslate"><span class="pre">custom2</span></code> that adds these capabilities:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">"structmember.h"</span><span class="cp"></span> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span><span class="p">;</span> <span class="cm">/* first name */</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">last</span><span class="p">;</span> <span class="cm">/* last name */</span> <span class="kt">int</span> <span class="n">number</span><span class="p">;</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">Custom_dealloc</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-></span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_new</span><span class="p">(</span><span class="n">PyTypeObject</span> <span class="o">*</span><span class="n">type</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">;</span> <span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">type</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">number</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_init</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kwlist</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="s">"last"</span><span class="p">,</span> <span class="s">"number"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">last</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTupleAndKeywords</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">,</span> <span class="s">"|OOi"</span><span class="p">,</span> <span class="n">kwlist</span><span class="p">,</span> <span class="o">&</span><span class="n">first</span><span class="p">,</span> <span class="o">&</span><span class="n">last</span><span class="p">,</span> <span class="o">&</span><span class="n">self</span><span class="o">-></span><span class="n">number</span><span class="p">))</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">last</span><span class="p">;</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMemberDef</span> <span class="n">Custom_members</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="n">T_OBJECT_EX</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">first</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"first name"</span><span class="p">},</span> <span class="p">{</span><span class="s">"last"</span><span class="p">,</span> <span class="n">T_OBJECT_EX</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">last</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"last name"</span><span class="p">},</span> <span class="p">{</span><span class="s">"number"</span><span class="p">,</span> <span class="n">T_INT</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">number</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"custom number"</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_name</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">Py_UNUSED</span><span class="p">(</span><span class="n">ignored</span><span class="p">))</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_AttributeError</span><span class="p">,</span> <span class="s">"first"</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_AttributeError</span><span class="p">,</span> <span class="s">"last"</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">"%S %S"</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">Custom_methods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"name"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span> <span class="n">Custom_name</span><span class="p">,</span> <span class="n">METH_NOARGS</span><span class="p">,</span> <span class="s">"Return the name, combining the first and last name"</span> <span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">CustomType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom2.Custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">Custom_new</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_init</span> <span class="o">=</span> <span class="p">(</span><span class="n">initproc</span><span class="p">)</span> <span class="n">Custom_init</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_dealloc</span> <span class="o">=</span> <span class="p">(</span><span class="n">destructor</span><span class="p">)</span> <span class="n">Custom_dealloc</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_members</span> <span class="o">=</span> <span class="n">Custom_members</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_methods</span> <span class="o">=</span> <span class="n">Custom_methods</span><span class="p">,</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyModuleDef</span> <span class="n">custommodule</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span> <span class="p">.</span><span class="n">m_name</span> <span class="o">=</span> <span class="s">"custom2"</span><span class="p">,</span> <span class="p">.</span><span class="n">m_doc</span> <span class="o">=</span> <span class="s">"Example module that creates an extension type."</span><span class="p">,</span> <span class="p">.</span><span class="n">m_size</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">};</span> <span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_custom2</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">m</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">custommodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"Custom"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>This version of the module has a number of changes.</p> <p>We’ve added an extra include:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><structmember.h></span><span class="cp"></span> </pre></div> </div> <p>This include provides declarations that we use to handle attributes, as described a bit later.</p> <p>The <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> type now has three data attributes in its C struct, <em>first</em>, <em>last</em>, and <em>number</em>. The <em>first</em> and <em>last</em> variables are Python strings containing first and last names. The <em>number</em> attribute is a C integer.</p> <p>The object structure is updated accordingly:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span><span class="p">;</span> <span class="cm">/* first name */</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">last</span><span class="p">;</span> <span class="cm">/* last name */</span> <span class="kt">int</span> <span class="n">number</span><span class="p">;</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> </pre></div> </div> <p>Because we now have data to manage, we have to be more careful about object allocation and deallocation. At a minimum, we need a deallocation method:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">Custom_dealloc</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-></span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <p>which is assigned to the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> member:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_dealloc</span> <span class="o">=</span> <span class="p">(</span><span class="n">destructor</span><span class="p">)</span> <span class="n">Custom_dealloc</span><span class="p">,</span> </pre></div> </div> <p>This method first clears the reference counts of the two Python attributes. <a class="reference internal" href="../c-api/refcounting.html#c.Py_XDECREF" title="Py_XDECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_XDECREF()</span></code></a> correctly handles the case where its argument is <em>NULL</em> (which might happen here if <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> failed midway). It then calls the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_free" title="PyTypeObject.tp_free"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_free</span></code></a> member of the object’s type (computed by <code class="docutils literal notranslate"><span class="pre">Py_TYPE(self)</span></code>) to free the object’s memory. Note that the object’s type might not be <code class="xref py py-class docutils literal notranslate"><span class="pre">CustomType</span></code>, because the object may be an instance of a subclass.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">The explicit cast to <code class="docutils literal notranslate"><span class="pre">destructor</span></code> above is needed because we defined <code class="docutils literal notranslate"><span class="pre">Custom_dealloc</span></code> to take a <code class="docutils literal notranslate"><span class="pre">CustomObject</span> <span class="pre">*</span></code> argument, but the <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code> function pointer expects to receive a <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code> argument. Otherwise, the compiler will emit a warning. This is object-oriented polymorphism, in C!</p> </div> <p>We want to make sure that the first and last names are initialized to empty strings, so we provide a <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> implementation:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_new</span><span class="p">(</span><span class="n">PyTypeObject</span> <span class="o">*</span><span class="n">type</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">;</span> <span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">type</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">number</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>and install it in the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> member:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">Custom_new</span><span class="p">,</span> </pre></div> </div> <p>The <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> handler is responsible for creating (as opposed to initializing) objects of the type. It is exposed in Python as the <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a> method. It is not required to define a <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> member, and indeed many extension types will simply reuse <a class="reference internal" href="../c-api/type.html#c.PyType_GenericNew" title="PyType_GenericNew"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GenericNew()</span></code></a> as done in the first version of the <code class="docutils literal notranslate"><span class="pre">Custom</span></code> type above. In this case, we use the <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> handler to initialize the <code class="docutils literal notranslate"><span class="pre">first</span></code> and <code class="docutils literal notranslate"><span class="pre">last</span></code> attributes to non-<em>NULL</em> default values.</p> <p><code class="docutils literal notranslate"><span class="pre">tp_new</span></code> is passed the type being instantiated (not necessarily <code class="docutils literal notranslate"><span class="pre">CustomType</span></code>, if a subclass is instantiated) and any arguments passed when the type was called, and is expected to return the instance created. <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> handlers always accept positional and keyword arguments, but they often ignore the arguments, leaving the argument handling to initializer (a.k.a. <code class="docutils literal notranslate"><span class="pre">tp_init</span></code> in C or <code class="docutils literal notranslate"><span class="pre">__init__</span></code> in Python) methods.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last"><code class="docutils literal notranslate"><span class="pre">tp_new</span></code> shouldn’t call <code class="docutils literal notranslate"><span class="pre">tp_init</span></code> explicitly, as the interpreter will do it itself.</p> </div> <p>The <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> implementation calls the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> slot to allocate memory:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">type</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> </pre></div> </div> <p>Since memory allocation may fail, we must check the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> result against <em>NULL</em> before proceeding.</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">We didn’t fill the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> slot ourselves. Rather <a class="reference internal" href="../c-api/type.html#c.PyType_Ready" title="PyType_Ready"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_Ready()</span></code></a> fills it for us by inheriting it from our base class, which is <a class="reference internal" href="../library/functions.html#object" title="object"><code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></a> by default. Most types use the default allocation strategy.</p> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">If you are creating a co-operative <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> (one that calls a base type’s <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> or <a class="reference internal" href="../reference/datamodel.html#object.__new__" title="object.__new__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__new__()</span></code></a>), you must <em>not</em> try to determine what method to call using method resolution order at runtime. Always statically determine what type you are going to call, and call its <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> directly, or via <code class="docutils literal notranslate"><span class="pre">type->tp_base->tp_new</span></code>. If you do not do this, Python subclasses of your type that also inherit from other Python-defined classes may not work correctly. (Specifically, you may not be able to create instances of such subclasses without getting a <a class="reference internal" href="../library/exceptions.html#TypeError" title="TypeError"><code class="xref py py-exc docutils literal notranslate"><span class="pre">TypeError</span></code></a>.)</p> </div> <p>We also define an initialization function which accepts arguments to provide initial values for our instance:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_init</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kwlist</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="s">"last"</span><span class="p">,</span> <span class="s">"number"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">last</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTupleAndKeywords</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">,</span> <span class="s">"|OOi"</span><span class="p">,</span> <span class="n">kwlist</span><span class="p">,</span> <span class="o">&</span><span class="n">first</span><span class="p">,</span> <span class="o">&</span><span class="n">last</span><span class="p">,</span> <span class="o">&</span><span class="n">self</span><span class="o">-></span><span class="n">number</span><span class="p">))</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">last</span><span class="p">;</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>by filling the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_init" title="PyTypeObject.tp_init"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_init</span></code></a> slot.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_init</span> <span class="o">=</span> <span class="p">(</span><span class="n">initproc</span><span class="p">)</span> <span class="n">Custom_init</span><span class="p">,</span> </pre></div> </div> <p>The <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_init" title="PyTypeObject.tp_init"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_init</span></code></a> slot is exposed in Python as the <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method. It is used to initialize an object after it’s created. Initializers always accept positional and keyword arguments, and they should return either <code class="docutils literal notranslate"><span class="pre">0</span></code> on success or <code class="docutils literal notranslate"><span class="pre">-1</span></code> on error.</p> <p>Unlike the <code class="docutils literal notranslate"><span class="pre">tp_new</span></code> handler, there is no guarantee that <code class="docutils literal notranslate"><span class="pre">tp_init</span></code> is called at all (for example, the <a class="reference internal" href="../library/pickle.html#module-pickle" title="pickle: Convert Python objects to streams of bytes and back."><code class="xref py py-mod docutils literal notranslate"><span class="pre">pickle</span></code></a> module by default doesn’t call <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> on unpickled instances). It can also be called multiple times. Anyone can call the <a class="reference internal" href="../reference/datamodel.html#object.__init__" title="object.__init__"><code class="xref py py-meth docutils literal notranslate"><span class="pre">__init__()</span></code></a> method on our objects. For this reason, we have to be extra careful when assigning the new attribute values. We might be tempted, for example to assign the <code class="docutils literal notranslate"><span class="pre">first</span></code> member like this:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>But this would be risky. Our type doesn’t restrict the type of the <code class="docutils literal notranslate"><span class="pre">first</span></code> member, so it could be any kind of object. It could have a destructor that causes code to be executed that tries to access the <code class="docutils literal notranslate"><span class="pre">first</span></code> member; or that destructor could release the <a class="reference internal" href="../glossary.html#term-global-interpreter-lock"><span class="xref std std-term">Global interpreter Lock</span></a> and let arbitrary code run in other threads that accesses and modifies our object.</p> <p>To be paranoid and protect ourselves against this possibility, we almost always reassign members before decrementing their reference counts. When don’t we have to do this?</p> <ul class="simple"> <li>when we absolutely know that the reference count is greater than 1;</li> <li>when we know that deallocation of the object <a class="footnote-reference" href="#id5" id="id1">[1]</a> will neither release the <a class="reference internal" href="../glossary.html#term-gil"><span class="xref std std-term">GIL</span></a> nor cause any calls back into our type’s code;</li> <li>when decrementing a reference count in a <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> handler on a type which doesn’t support cyclic garbage collection <a class="footnote-reference" href="#id6" id="id2">[2]</a>.</li> </ul> <p>We want to expose our instance variables as attributes. There are a number of ways to do that. The simplest way is to define member definitions:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyMemberDef</span> <span class="n">Custom_members</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="n">T_OBJECT_EX</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">first</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"first name"</span><span class="p">},</span> <span class="p">{</span><span class="s">"last"</span><span class="p">,</span> <span class="n">T_OBJECT_EX</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">last</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"last name"</span><span class="p">},</span> <span class="p">{</span><span class="s">"number"</span><span class="p">,</span> <span class="n">T_INT</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">number</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"custom number"</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> </pre></div> </div> <p>and put the definitions in the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_members" title="PyTypeObject.tp_members"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_members</span></code></a> slot:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_members</span> <span class="o">=</span> <span class="n">Custom_members</span><span class="p">,</span> </pre></div> </div> <p>Each member definition has a member name, type, offset, access flags and documentation string. See the <a class="reference internal" href="newtypes.html#generic-attribute-management"><span class="std std-ref">Generic Attribute Management</span></a> section below for details.</p> <p>A disadvantage of this approach is that it doesn’t provide a way to restrict the types of objects that can be assigned to the Python attributes. We expect the first and last names to be strings, but any Python objects can be assigned. Further, the attributes can be deleted, setting the C pointers to <em>NULL</em>. Even though we can make sure the members are initialized to non-<em>NULL</em> values, the members can be set to <em>NULL</em> if the attributes are deleted.</p> <p>We define a single method, <code class="xref py py-meth docutils literal notranslate"><span class="pre">Custom.name()</span></code>, that outputs the objects name as the concatenation of the first and last names.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_name</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_AttributeError</span><span class="p">,</span> <span class="s">"first"</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_AttributeError</span><span class="p">,</span> <span class="s">"last"</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">"%S %S"</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <p>The method is implemented as a C function that takes a <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> (or <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> subclass) instance as the first argument. Methods always take an instance as the first argument. Methods often take positional and keyword arguments as well, but in this case we don’t take any and don’t need to accept a positional argument tuple or keyword argument dictionary. This method is equivalent to the Python method:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">name</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="s2">"</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">first</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">last</span><span class="p">)</span> </pre></div> </div> <p>Note that we have to check for the possibility that our <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> and <code class="xref py py-attr docutils literal notranslate"><span class="pre">last</span></code> members are <em>NULL</em>. This is because they can be deleted, in which case they are set to <em>NULL</em>. It would be better to prevent deletion of these attributes and to restrict the attribute values to be strings. We’ll see how to do that in the next section.</p> <p>Now that we’ve defined the method, we need to create an array of method definitions:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">Custom_methods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"name"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span> <span class="n">Custom_name</span><span class="p">,</span> <span class="n">METH_NOARGS</span><span class="p">,</span> <span class="s">"Return the name, combining the first and last name"</span> <span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> </pre></div> </div> <p>(note that we used the <a class="reference internal" href="../c-api/structures.html#METH_NOARGS" title="METH_NOARGS"><code class="xref py py-const docutils literal notranslate"><span class="pre">METH_NOARGS</span></code></a> flag to indicate that the method is expecting no arguments other than <em>self</em>)</p> <p>and assign it to the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_methods" title="PyTypeObject.tp_methods"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_methods</span></code></a> slot:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_methods</span> <span class="o">=</span> <span class="n">Custom_methods</span><span class="p">,</span> </pre></div> </div> <p>Finally, we’ll make our type usable as a base class for subclassing. We’ve written our methods carefully so far so that they don’t make any assumptions about the type of the object being created or used, so all we need to do is to add the <a class="reference internal" href="../c-api/typeobj.html#Py_TPFLAGS_BASETYPE" title="Py_TPFLAGS_BASETYPE"><code class="xref py py-const docutils literal notranslate"><span class="pre">Py_TPFLAGS_BASETYPE</span></code></a> to our class flag definition:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span><span class="p">,</span> </pre></div> </div> <p>We rename <code class="xref c c-func docutils literal notranslate"><span class="pre">PyInit_custom()</span></code> to <code class="xref c c-func docutils literal notranslate"><span class="pre">PyInit_custom2()</span></code>, update the module name in the <a class="reference internal" href="../c-api/module.html#c.PyModuleDef" title="PyModuleDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyModuleDef</span></code></a> struct, and update the full class name in the <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> struct.</p> <p>Finally, we update our <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> file to build the new module:</p> <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">distutils.core</span> <span class="kn">import</span> <span class="n">setup</span><span class="p">,</span> <span class="n">Extension</span> <span class="n">setup</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"custom"</span><span class="p">,</span> <span class="n">version</span><span class="o">=</span><span class="s2">"1.0"</span><span class="p">,</span> <span class="n">ext_modules</span><span class="o">=</span><span class="p">[</span> <span class="n">Extension</span><span class="p">(</span><span class="s2">"custom"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"custom.c"</span><span class="p">]),</span> <span class="n">Extension</span><span class="p">(</span><span class="s2">"custom2"</span><span class="p">,</span> <span class="p">[</span><span class="s2">"custom2.c"</span><span class="p">]),</span> <span class="p">])</span> </pre></div> </div> </div> <div class="section" id="providing-finer-control-over-data-attributes"> <h2>2.3. Providing finer control over data attributes<a class="headerlink" href="#providing-finer-control-over-data-attributes" title="Permalink to this headline">¶</a></h2> <p>In this section, we’ll provide finer control over how the <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> and <code class="xref py py-attr docutils literal notranslate"><span class="pre">last</span></code> attributes are set in the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> example. In the previous version of our module, the instance variables <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> and <code class="xref py py-attr docutils literal notranslate"><span class="pre">last</span></code> could be set to non-string values or even deleted. We want to make sure that these attributes always contain strings.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">"structmember.h"</span><span class="cp"></span> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span><span class="p">;</span> <span class="cm">/* first name */</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">last</span><span class="p">;</span> <span class="cm">/* last name */</span> <span class="kt">int</span> <span class="n">number</span><span class="p">;</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">Custom_dealloc</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-></span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_new</span><span class="p">(</span><span class="n">PyTypeObject</span> <span class="o">*</span><span class="n">type</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">;</span> <span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">type</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">number</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_init</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kwlist</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="s">"last"</span><span class="p">,</span> <span class="s">"number"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">last</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTupleAndKeywords</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">,</span> <span class="s">"|UUi"</span><span class="p">,</span> <span class="n">kwlist</span><span class="p">,</span> <span class="o">&</span><span class="n">first</span><span class="p">,</span> <span class="o">&</span><span class="n">last</span><span class="p">,</span> <span class="o">&</span><span class="n">self</span><span class="o">-></span><span class="n">number</span><span class="p">))</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">last</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMemberDef</span> <span class="n">Custom_members</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"number"</span><span class="p">,</span> <span class="n">T_INT</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">number</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"custom number"</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_getfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="k">return</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_setfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"Cannot delete the first attribute"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyUnicode_Check</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"The first attribute value must be a string"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_getlast</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_setlast</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"Cannot delete the last attribute"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyUnicode_Check</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"The last attribute value must be a string"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyGetSetDef</span> <span class="n">Custom_getsetters</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getfirst</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setfirst</span><span class="p">,</span> <span class="s">"first name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="s">"last"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getlast</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setlast</span><span class="p">,</span> <span class="s">"last name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_name</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">Py_UNUSED</span><span class="p">(</span><span class="n">ignored</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span> <span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">"%S %S"</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">Custom_methods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"name"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span> <span class="n">Custom_name</span><span class="p">,</span> <span class="n">METH_NOARGS</span><span class="p">,</span> <span class="s">"Return the name, combining the first and last name"</span> <span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">CustomType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom3.Custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">Custom_new</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_init</span> <span class="o">=</span> <span class="p">(</span><span class="n">initproc</span><span class="p">)</span> <span class="n">Custom_init</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_dealloc</span> <span class="o">=</span> <span class="p">(</span><span class="n">destructor</span><span class="p">)</span> <span class="n">Custom_dealloc</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_members</span> <span class="o">=</span> <span class="n">Custom_members</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_methods</span> <span class="o">=</span> <span class="n">Custom_methods</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_getset</span> <span class="o">=</span> <span class="n">Custom_getsetters</span><span class="p">,</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyModuleDef</span> <span class="n">custommodule</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span> <span class="p">.</span><span class="n">m_name</span> <span class="o">=</span> <span class="s">"custom3"</span><span class="p">,</span> <span class="p">.</span><span class="n">m_doc</span> <span class="o">=</span> <span class="s">"Example module that creates an extension type."</span><span class="p">,</span> <span class="p">.</span><span class="n">m_size</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">};</span> <span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_custom3</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">m</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">custommodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"Custom"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>To provide greater control, over the <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> and <code class="xref py py-attr docutils literal notranslate"><span class="pre">last</span></code> attributes, we’ll use custom getter and setter functions. Here are the functions for getting and setting the <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> attribute:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_getfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="k">return</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_setfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"Cannot delete the first attribute"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyUnicode_Check</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"The first attribute value must be a string"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>The getter function is passed a <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> object and a “closure”, which is a void pointer. In this case, the closure is ignored. (The closure supports an advanced usage in which definition data is passed to the getter and setter. This could, for example, be used to allow a single set of getter and setter functions that decide the attribute to get or set based on data in the closure.)</p> <p>The setter function is passed the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> object, the new value, and the closure. The new value may be <em>NULL</em>, in which case the attribute is being deleted. In our setter, we raise an error if the attribute is deleted or if its new value is not a string.</p> <p>We create an array of <a class="reference internal" href="../c-api/structures.html#c.PyGetSetDef" title="PyGetSetDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyGetSetDef</span></code></a> structures:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyGetSetDef</span> <span class="n">Custom_getsetters</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getfirst</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setfirst</span><span class="p">,</span> <span class="s">"first name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="s">"last"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getlast</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setlast</span><span class="p">,</span> <span class="s">"last name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> </pre></div> </div> <p>and register it in the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_getset" title="PyTypeObject.tp_getset"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_getset</span></code></a> slot:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_getset</span> <span class="o">=</span> <span class="n">Custom_getsetters</span><span class="p">,</span> </pre></div> </div> <p>The last item in a <a class="reference internal" href="../c-api/structures.html#c.PyGetSetDef" title="PyGetSetDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyGetSetDef</span></code></a> structure is the “closure” mentioned above. In this case, we aren’t using a closure, so we just pass <em>NULL</em>.</p> <p>We also remove the member definitions for these attributes:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="n">PyMemberDef</span> <span class="n">Custom_members</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"number"</span><span class="p">,</span> <span class="n">T_INT</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">number</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"custom number"</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> </pre></div> </div> <p>We also need to update the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_init" title="PyTypeObject.tp_init"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_init</span></code></a> handler to only allow strings <a class="footnote-reference" href="#id7" id="id3">[3]</a> to be passed:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_init</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kwlist</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="s">"last"</span><span class="p">,</span> <span class="s">"number"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">last</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTupleAndKeywords</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">,</span> <span class="s">"|UUi"</span><span class="p">,</span> <span class="n">kwlist</span><span class="p">,</span> <span class="o">&</span><span class="n">first</span><span class="p">,</span> <span class="o">&</span><span class="n">last</span><span class="p">,</span> <span class="o">&</span><span class="n">self</span><span class="o">-></span><span class="n">number</span><span class="p">))</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">last</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>With these changes, we can assure that the <code class="docutils literal notranslate"><span class="pre">first</span></code> and <code class="docutils literal notranslate"><span class="pre">last</span></code> members are never <em>NULL</em> so we can remove checks for <em>NULL</em> values in almost all cases. This means that most of the <a class="reference internal" href="../c-api/refcounting.html#c.Py_XDECREF" title="Py_XDECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_XDECREF()</span></code></a> calls can be converted to <a class="reference internal" href="../c-api/refcounting.html#c.Py_DECREF" title="Py_DECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_DECREF()</span></code></a> calls. The only place we can’t change these calls is in the <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code> implementation, where there is the possibility that the initialization of these members failed in <code class="docutils literal notranslate"><span class="pre">tp_new</span></code>.</p> <p>We also rename the module initialization function and module name in the initialization function, as we did before, and we add an extra definition to the <code class="file docutils literal notranslate"><span class="pre">setup.py</span></code> file.</p> </div> <div class="section" id="supporting-cyclic-garbage-collection"> <h2>2.4. Supporting cyclic garbage collection<a class="headerlink" href="#supporting-cyclic-garbage-collection" title="Permalink to this headline">¶</a></h2> <p>Python has a <a class="reference internal" href="../glossary.html#term-garbage-collection"><span class="xref std std-term">cyclic garbage collector (GC)</span></a> that can identify unneeded objects even when their reference counts are not zero. This can happen when objects are involved in cycles. For example, consider:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">l</span> <span class="o">=</span> <span class="p">[]</span> <span class="gp">>>> </span><span class="n">l</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">l</span><span class="p">)</span> <span class="gp">>>> </span><span class="k">del</span> <span class="n">l</span> </pre></div> </div> <p>In this example, we create a list that contains itself. When we delete it, it still has a reference from itself. Its reference count doesn’t drop to zero. Fortunately, Python’s cyclic garbage collector will eventually figure out that the list is garbage and free it.</p> <p>In the second version of the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> example, we allowed any kind of object to be stored in the <code class="xref py py-attr docutils literal notranslate"><span class="pre">first</span></code> or <code class="xref py py-attr docutils literal notranslate"><span class="pre">last</span></code> attributes <a class="footnote-reference" href="#id8" id="id4">[4]</a>. Besides, in the second and third versions, we allowed subclassing <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code>, and subclasses may add arbitrary attributes. For any of those two reasons, <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> objects can participate in cycles:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">custom3</span> <span class="gp">>>> </span><span class="k">class</span> <span class="nc">Derived</span><span class="p">(</span><span class="n">custom3</span><span class="o">.</span><span class="n">Custom</span><span class="p">):</span> <span class="k">pass</span> <span class="gp">...</span> <span class="gp">>>> </span><span class="n">n</span> <span class="o">=</span> <span class="n">Derived</span><span class="p">()</span> <span class="gp">>>> </span><span class="n">n</span><span class="o">.</span><span class="n">some_attribute</span> <span class="o">=</span> <span class="n">n</span> </pre></div> </div> <p>To allow a <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> instance participating in a reference cycle to be properly detected and collected by the cyclic GC, our <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> type needs to fill two additional slots and to enable a flag that enables these slots:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">"structmember.h"</span><span class="cp"></span> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyObject_HEAD</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span><span class="p">;</span> <span class="cm">/* first name */</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">last</span><span class="p">;</span> <span class="cm">/* last name */</span> <span class="kt">int</span> <span class="n">number</span><span class="p">;</span> <span class="p">}</span> <span class="n">CustomObject</span><span class="p">;</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_traverse</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">visitproc</span> <span class="n">visit</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_VISIT</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_VISIT</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_clear</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">void</span> <span class="nf">Custom_dealloc</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject_GC_UnTrack</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="n">Custom_clear</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-></span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_new</span><span class="p">(</span><span class="n">PyTypeObject</span> <span class="o">*</span><span class="n">type</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">;</span> <span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">type</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">PyUnicode_FromString</span><span class="p">(</span><span class="s">""</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="p">}</span> <span class="n">self</span><span class="o">-></span><span class="n">number</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_init</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">static</span> <span class="kt">char</span> <span class="o">*</span><span class="n">kwlist</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="s">"last"</span><span class="p">,</span> <span class="s">"number"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">last</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">,</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyArg_ParseTupleAndKeywords</span><span class="p">(</span><span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">,</span> <span class="s">"|UUi"</span><span class="p">,</span> <span class="n">kwlist</span><span class="p">,</span> <span class="o">&</span><span class="n">first</span><span class="p">,</span> <span class="o">&</span><span class="n">last</span><span class="p">,</span> <span class="o">&</span><span class="n">self</span><span class="o">-></span><span class="n">number</span><span class="p">))</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">first</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">last</span><span class="p">;</span> <span class="n">Py_DECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMemberDef</span> <span class="n">Custom_members</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"number"</span><span class="p">,</span> <span class="n">T_INT</span><span class="p">,</span> <span class="n">offsetof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">,</span> <span class="n">number</span><span class="p">),</span> <span class="mi">0</span><span class="p">,</span> <span class="s">"custom number"</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_getfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="k">return</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_setfirst</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"Cannot delete the first attribute"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyUnicode_Check</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"The first attribute value must be a string"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_getlast</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_setlast</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">value</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">closure</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">value</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"Cannot delete the last attribute"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">PyUnicode_Check</span><span class="p">(</span><span class="n">value</span><span class="p">))</span> <span class="p">{</span> <span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_TypeError</span><span class="p">,</span> <span class="s">"The last attribute value must be a string"</span><span class="p">);</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">value</span><span class="p">);</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyGetSetDef</span> <span class="n">Custom_getsetters</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"first"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getfirst</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setfirst</span><span class="p">,</span> <span class="s">"first name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="s">"last"</span><span class="p">,</span> <span class="p">(</span><span class="n">getter</span><span class="p">)</span> <span class="n">Custom_getlast</span><span class="p">,</span> <span class="p">(</span><span class="n">setter</span><span class="p">)</span> <span class="n">Custom_setlast</span><span class="p">,</span> <span class="s">"last name"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">Custom_name</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">Py_UNUSED</span><span class="p">(</span><span class="n">ignored</span><span class="p">))</span> <span class="p">{</span> <span class="k">return</span> <span class="n">PyUnicode_FromFormat</span><span class="p">(</span><span class="s">"%S %S"</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">,</span> <span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">Custom_methods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"name"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span> <span class="n">Custom_name</span><span class="p">,</span> <span class="n">METH_NOARGS</span><span class="p">,</span> <span class="s">"Return the name, combining the first and last name"</span> <span class="p">},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">}</span> <span class="cm">/* Sentinel */</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">CustomType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"custom4.Custom"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"Custom objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">CustomObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_HAVE_GC</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_new</span> <span class="o">=</span> <span class="n">Custom_new</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_init</span> <span class="o">=</span> <span class="p">(</span><span class="n">initproc</span><span class="p">)</span> <span class="n">Custom_init</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_dealloc</span> <span class="o">=</span> <span class="p">(</span><span class="n">destructor</span><span class="p">)</span> <span class="n">Custom_dealloc</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_traverse</span> <span class="o">=</span> <span class="p">(</span><span class="n">traverseproc</span><span class="p">)</span> <span class="n">Custom_traverse</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_clear</span> <span class="o">=</span> <span class="p">(</span><span class="n">inquiry</span><span class="p">)</span> <span class="n">Custom_clear</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_members</span> <span class="o">=</span> <span class="n">Custom_members</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_methods</span> <span class="o">=</span> <span class="n">Custom_methods</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_getset</span> <span class="o">=</span> <span class="n">Custom_getsetters</span><span class="p">,</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyModuleDef</span> <span class="n">custommodule</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span> <span class="p">.</span><span class="n">m_name</span> <span class="o">=</span> <span class="s">"custom4"</span><span class="p">,</span> <span class="p">.</span><span class="n">m_doc</span> <span class="o">=</span> <span class="s">"Example module that creates an extension type."</span><span class="p">,</span> <span class="p">.</span><span class="n">m_size</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">};</span> <span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_custom4</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">m</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">custommodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"Custom"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">CustomType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>First, the traversal method lets the cyclic GC know about subobjects that could participate in cycles:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_traverse</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">visitproc</span> <span class="n">visit</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">vret</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">)</span> <span class="p">{</span> <span class="n">vret</span> <span class="o">=</span> <span class="n">visit</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">,</span> <span class="n">arg</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">vret</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">vret</span><span class="p">;</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">)</span> <span class="p">{</span> <span class="n">vret</span> <span class="o">=</span> <span class="n">visit</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">,</span> <span class="n">arg</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">vret</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">vret</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>For each subobject that can participate in cycles, we need to call the <code class="xref c c-func docutils literal notranslate"><span class="pre">visit()</span></code> function, which is passed to the traversal method. The <code class="xref c c-func docutils literal notranslate"><span class="pre">visit()</span></code> function takes as arguments the subobject and the extra argument <em>arg</em> passed to the traversal method. It returns an integer value that must be returned if it is non-zero.</p> <p>Python provides a <a class="reference internal" href="../c-api/gcsupport.html#c.Py_VISIT" title="Py_VISIT"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_VISIT()</span></code></a> macro that automates calling visit functions. With <a class="reference internal" href="../c-api/gcsupport.html#c.Py_VISIT" title="Py_VISIT"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_VISIT()</span></code></a>, we can minimize the amount of boilerplate in <code class="docutils literal notranslate"><span class="pre">Custom_traverse</span></code>:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_traverse</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">visitproc</span> <span class="n">visit</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_VISIT</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_VISIT</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <div class="admonition note"> <p class="first admonition-title">Note</p> <p class="last">The <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_traverse" title="PyTypeObject.tp_traverse"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_traverse</span></code></a> implementation must name its arguments exactly <em>visit</em> and <em>arg</em> in order to use <a class="reference internal" href="../c-api/gcsupport.html#c.Py_VISIT" title="Py_VISIT"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_VISIT()</span></code></a>.</p> </div> <p>Second, we need to provide a method for clearing any subobjects that can participate in cycles:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">Custom_clear</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">);</span> <span class="n">Py_CLEAR</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">last</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>Notice the use of the <a class="reference internal" href="../c-api/refcounting.html#c.Py_CLEAR" title="Py_CLEAR"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_CLEAR()</span></code></a> macro. It is the recommended and safe way to clear data attributes of arbitrary types while decrementing their reference counts. If you were to call <a class="reference internal" href="../c-api/refcounting.html#c.Py_XDECREF" title="Py_XDECREF"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_XDECREF()</span></code></a> instead on the attribute before setting it to <em>NULL</em>, there is a possibility that the attribute’s destructor would call back into code that reads the attribute again (<em>especially</em> if there is a reference cycle).</p> <div class="admonition note"> <p class="first admonition-title">Note</p> <p>You could emulate <a class="reference internal" href="../c-api/refcounting.html#c.Py_CLEAR" title="Py_CLEAR"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_CLEAR()</span></code></a> by writing:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span> <span class="o">*</span><span class="n">tmp</span><span class="p">;</span> <span class="n">tmp</span> <span class="o">=</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span><span class="p">;</span> <span class="n">self</span><span class="o">-></span><span class="n">first</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> </pre></div> </div> <p class="last">Nevertheless, it is much easier and less error-prone to always use <a class="reference internal" href="../c-api/refcounting.html#c.Py_CLEAR" title="Py_CLEAR"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_CLEAR()</span></code></a> when deleting an attribute. Don’t try to micro-optimize at the expense of robustness!</p> </div> <p>The deallocator <code class="docutils literal notranslate"><span class="pre">Custom_dealloc</span></code> may call arbitrary code when clearing attributes. It means the circular GC can be triggered inside the function. Since the GC assumes reference count is not zero, we need to untrack the object from the GC by calling <a class="reference internal" href="../c-api/gcsupport.html#c.PyObject_GC_UnTrack" title="PyObject_GC_UnTrack"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GC_UnTrack()</span></code></a> before clearing members. Here is our reimplemented deallocator using <a class="reference internal" href="../c-api/gcsupport.html#c.PyObject_GC_UnTrack" title="PyObject_GC_UnTrack"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GC_UnTrack()</span></code></a> and <code class="docutils literal notranslate"><span class="pre">Custom_clear</span></code>:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">void</span> <span class="nf">Custom_dealloc</span><span class="p">(</span><span class="n">CustomObject</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject_GC_UnTrack</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="n">Custom_clear</span><span class="p">(</span><span class="n">self</span><span class="p">);</span> <span class="n">Py_TYPE</span><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="o">-></span><span class="n">tp_free</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <p>Finally, we add the <a class="reference internal" href="../c-api/typeobj.html#Py_TPFLAGS_HAVE_GC" title="Py_TPFLAGS_HAVE_GC"><code class="xref py py-const docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_GC</span></code></a> flag to the class flags:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_HAVE_GC</span><span class="p">,</span> </pre></div> </div> <p>That’s pretty much it. If we had written custom <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> or <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_free" title="PyTypeObject.tp_free"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_free</span></code></a> handlers, we’d need to modify them for cyclic garbage collection. Most extensions will use the versions automatically provided.</p> </div> <div class="section" id="subclassing-other-types"> <h2>2.5. Subclassing other types<a class="headerlink" href="#subclassing-other-types" title="Permalink to this headline">¶</a></h2> <p>It is possible to create new extension types that are derived from existing types. It is easiest to inherit from the built in types, since an extension can easily use the <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> it needs. It can be difficult to share these <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> structures between extension modules.</p> <p>In this example we will create a <code class="xref py py-class docutils literal notranslate"><span class="pre">SubList</span></code> type that inherits from the built-in <a class="reference internal" href="../library/stdtypes.html#list" title="list"><code class="xref py py-class docutils literal notranslate"><span class="pre">list</span></code></a> type. The new type will be completely compatible with regular lists, but will have an additional <code class="xref py py-meth docutils literal notranslate"><span class="pre">increment()</span></code> method that increases an internal counter:</p> <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">sublist</span> <span class="gp">>>> </span><span class="n">s</span> <span class="o">=</span> <span class="n">sublist</span><span class="o">.</span><span class="n">SubList</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">))</span> <span class="gp">>>> </span><span class="n">s</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="gp">>>> </span><span class="k">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="go">6</span> <span class="gp">>>> </span><span class="k">print</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">increment</span><span class="p">())</span> <span class="go">1</span> <span class="gp">>>> </span><span class="k">print</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">increment</span><span class="p">())</span> <span class="go">2</span> </pre></div> </div> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span> <span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyListObject</span> <span class="n">list</span><span class="p">;</span> <span class="kt">int</span> <span class="n">state</span><span class="p">;</span> <span class="p">}</span> <span class="n">SubListObject</span><span class="p">;</span> <span class="k">static</span> <span class="n">PyObject</span> <span class="o">*</span> <span class="nf">SubList_increment</span><span class="p">(</span><span class="n">SubListObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">unused</span><span class="p">)</span> <span class="p">{</span> <span class="n">self</span><span class="o">-></span><span class="n">state</span><span class="o">++</span><span class="p">;</span> <span class="k">return</span> <span class="n">PyLong_FromLong</span><span class="p">(</span><span class="n">self</span><span class="o">-></span><span class="n">state</span><span class="p">);</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyMethodDef</span> <span class="n">SubList_methods</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{</span> <span class="p">{</span><span class="s">"increment"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyCFunction</span><span class="p">)</span> <span class="n">SubList_increment</span><span class="p">,</span> <span class="n">METH_NOARGS</span><span class="p">,</span> <span class="n">PyDoc_STR</span><span class="p">(</span><span class="s">"increment state counter"</span><span class="p">)},</span> <span class="p">{</span><span class="nb">NULL</span><span class="p">},</span> <span class="p">};</span> <span class="k">static</span> <span class="kt">int</span> <span class="nf">SubList_init</span><span class="p">(</span><span class="n">SubListObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyList_Type</span><span class="p">.</span><span class="n">tp_init</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">self</span><span class="o">-></span><span class="n">state</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="k">static</span> <span class="n">PyTypeObject</span> <span class="n">SubListType</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyVarObject_HEAD_INIT</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="p">.</span><span class="n">tp_name</span> <span class="o">=</span> <span class="s">"sublist.SubList"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_doc</span> <span class="o">=</span> <span class="s">"SubList objects"</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_basicsize</span> <span class="o">=</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">SubListObject</span><span class="p">),</span> <span class="p">.</span><span class="n">tp_itemsize</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_flags</span> <span class="o">=</span> <span class="n">Py_TPFLAGS_DEFAULT</span> <span class="o">|</span> <span class="n">Py_TPFLAGS_BASETYPE</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_init</span> <span class="o">=</span> <span class="p">(</span><span class="n">initproc</span><span class="p">)</span> <span class="n">SubList_init</span><span class="p">,</span> <span class="p">.</span><span class="n">tp_methods</span> <span class="o">=</span> <span class="n">SubList_methods</span><span class="p">,</span> <span class="p">};</span> <span class="k">static</span> <span class="n">PyModuleDef</span> <span class="n">sublistmodule</span> <span class="o">=</span> <span class="p">{</span> <span class="n">PyModuleDef_HEAD_INIT</span><span class="p">,</span> <span class="p">.</span><span class="n">m_name</span> <span class="o">=</span> <span class="s">"sublist"</span><span class="p">,</span> <span class="p">.</span><span class="n">m_doc</span> <span class="o">=</span> <span class="s">"Example module that creates an extension type."</span><span class="p">,</span> <span class="p">.</span><span class="n">m_size</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="p">};</span> <span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_sublist</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">m</span><span class="p">;</span> <span class="n">SubListType</span><span class="p">.</span><span class="n">tp_base</span> <span class="o">=</span> <span class="o">&</span><span class="n">PyList_Type</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">SubListType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">sublistmodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">SubListType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"SubList"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">SubListType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>As you can see, the source code closely resembles the <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> examples in previous sections. We will break down the main differences between them.</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span> <span class="n">PyListObject</span> <span class="n">list</span><span class="p">;</span> <span class="kt">int</span> <span class="n">state</span><span class="p">;</span> <span class="p">}</span> <span class="n">SubListObject</span><span class="p">;</span> </pre></div> </div> <p>The primary difference for derived type objects is that the base type’s object structure must be the first value. The base type will already include the <a class="reference internal" href="../c-api/structures.html#c.PyObject_HEAD" title="PyObject_HEAD"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_HEAD()</span></code></a> at the beginning of its structure.</p> <p>When a Python object is a <code class="xref py py-class docutils literal notranslate"><span class="pre">SubList</span></code> instance, its <code class="docutils literal notranslate"><span class="pre">PyObject</span> <span class="pre">*</span></code> pointer can be safely cast to both <code class="docutils literal notranslate"><span class="pre">PyListObject</span> <span class="pre">*</span></code> and <code class="docutils literal notranslate"><span class="pre">SubListObject</span> <span class="pre">*</span></code>:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span> <span class="kt">int</span> <span class="nf">SubList_init</span><span class="p">(</span><span class="n">SubListObject</span> <span class="o">*</span><span class="n">self</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="n">PyObject</span> <span class="o">*</span><span class="n">kwds</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyList_Type</span><span class="p">.</span><span class="n">tp_init</span><span class="p">((</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="n">kwds</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span> <span class="n">self</span><span class="o">-></span><span class="n">state</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>We see above how to call through to the <code class="xref py py-attr docutils literal notranslate"><span class="pre">__init__</span></code> method of the base type.</p> <p>This pattern is important when writing a type with custom <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> and <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> members. The <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a> handler should not actually create the memory for the object with its <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a>, but let the base class handle it by calling its own <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_new" title="PyTypeObject.tp_new"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_new</span></code></a>.</p> <p>The <a class="reference internal" href="../c-api/type.html#c.PyTypeObject" title="PyTypeObject"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyTypeObject</span></code></a> struct supports a <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_base" title="PyTypeObject.tp_base"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_base</span></code></a> specifying the type’s concrete base class. Due to cross-platform compiler issues, you can’t fill that field directly with a reference to <a class="reference internal" href="../c-api/list.html#c.PyList_Type" title="PyList_Type"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyList_Type</span></code></a>; it should be done later in the module initialization function:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyMODINIT_FUNC</span> <span class="nf">PyInit_sublist</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span> <span class="n">PyObject</span><span class="o">*</span> <span class="n">m</span><span class="p">;</span> <span class="n">SubListType</span><span class="p">.</span><span class="n">tp_base</span> <span class="o">=</span> <span class="o">&</span><span class="n">PyList_Type</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyType_Ready</span><span class="p">(</span><span class="o">&</span><span class="n">SubListType</span><span class="p">)</span> <span class="o"><</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">m</span> <span class="o">=</span> <span class="n">PyModule_Create</span><span class="p">(</span><span class="o">&</span><span class="n">sublistmodule</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">m</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="o">&</span><span class="n">SubListType</span><span class="p">);</span> <span class="n">PyModule_AddObject</span><span class="p">(</span><span class="n">m</span><span class="p">,</span> <span class="s">"SubList"</span><span class="p">,</span> <span class="p">(</span><span class="n">PyObject</span> <span class="o">*</span><span class="p">)</span> <span class="o">&</span><span class="n">SubListType</span><span class="p">);</span> <span class="k">return</span> <span class="n">m</span><span class="p">;</span> <span class="p">}</span> </pre></div> </div> <p>Before calling <a class="reference internal" href="../c-api/type.html#c.PyType_Ready" title="PyType_Ready"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_Ready()</span></code></a>, the type structure must have the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_base" title="PyTypeObject.tp_base"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_base</span></code></a> slot filled in. When we are deriving an existing type, it is not necessary to fill out the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_alloc" title="PyTypeObject.tp_alloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_alloc</span></code></a> slot with <a class="reference internal" href="../c-api/type.html#c.PyType_GenericNew" title="PyType_GenericNew"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GenericNew()</span></code></a> – the allocation function from the base type will be inherited.</p> <p>After that, calling <a class="reference internal" href="../c-api/type.html#c.PyType_Ready" title="PyType_Ready"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_Ready()</span></code></a> and adding the type object to the module is the same as with the basic <code class="xref py py-class docutils literal notranslate"><span class="pre">Custom</span></code> examples.</p> <p class="rubric">Footnotes</p> <table class="docutils footnote" frame="void" id="id5" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id1">[1]</a></td><td>This is true when we know that the object is a basic type, like a string or a float.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id6" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id2">[2]</a></td><td>We relied on this in the <a class="reference internal" href="../c-api/typeobj.html#c.PyTypeObject.tp_dealloc" title="PyTypeObject.tp_dealloc"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a> handler in this example, because our type doesn’t support garbage collection.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id7" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id3">[3]</a></td><td>We now know that the first and last members are strings, so perhaps we could be less careful about decrementing their reference counts, however, we accept instances of string subclasses. Even though deallocating normal strings won’t call back into our objects, we can’t guarantee that deallocating an instance of a string subclass won’t call back into our objects.</td></tr> </tbody> </table> <table class="docutils footnote" frame="void" id="id8" rules="none"> <colgroup><col class="label" /><col /></colgroup> <tbody valign="top"> <tr><td class="label"><a class="fn-backref" href="#id4">[4]</a></td><td>Also, even with our attributes restricted to strings instances, the user could pass arbitrary <a class="reference internal" href="../library/stdtypes.html#str" title="str"><code class="xref py py-class docutils literal notranslate"><span class="pre">str</span></code></a> subclasses and therefore still create reference cycles.</td></tr> </tbody> </table> </div> </div> </div> </div> </div> <div class="sphinxsidebar" role="navigation" aria-label="main navigation"> <div class="sphinxsidebarwrapper"> <h3><a href="../contents.html">Table Of Contents</a></h3> <ul> <li><a class="reference internal" href="#">2. Defining Extension Types: Tutorial</a><ul> <li><a class="reference internal" href="#the-basics">2.1. The Basics</a></li> <li><a class="reference internal" href="#adding-data-and-methods-to-the-basic-example">2.2. Adding data and methods to the Basic example</a></li> <li><a class="reference internal" href="#providing-finer-control-over-data-attributes">2.3. Providing finer control over data attributes</a></li> <li><a class="reference internal" href="#supporting-cyclic-garbage-collection">2.4. Supporting cyclic garbage collection</a></li> <li><a class="reference internal" href="#subclassing-other-types">2.5. Subclassing other types</a></li> </ul> </li> </ul> <h4>Previous topic</h4> <p class="topless"><a href="extending.html" title="previous chapter">1. Extending Python with C or C++</a></p> <h4>Next topic</h4> <p class="topless"><a href="newtypes.html" title="next chapter">3. Defining Extension Types: Assorted Topics</a></p> <div role="note" aria-label="source link"> <h3>This Page</h3> <ul class="this-page-menu"> <li><a href="../bugs.html">Report a Bug</a></li> <li> <a href="https://github.com/python/cpython/blob/3.6/Doc/extending/newtypes_tutorial.rst" rel="nofollow">Show Source </a> </li> </ul> </div> </div> </div> <div class="clearer"></div> </div> <div class="related" role="navigation" aria-label="related navigation"> <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="newtypes.html" title="3. Defining Extension Types: Assorted Topics" >next</a> |</li> <li class="right" > <a href="extending.html" title="1. Extending Python with C or C++" >previous</a> |</li> <li><img src="../_static/py.png" alt="" style="vertical-align: middle; margin-top: -1px"/></li> <li><a href="https://www.python.org/">Python</a> »</li> <li> <a href="../index.html">3.6.7 Documentation</a> » </li> <li class="nav-item nav-item-1"><a href="index.html" >Extending and Embedding the Python Interpreter</a> »</li> <li class="right"> <div class="inline-search" style="display: none" role="search"> <form class="inline-search" action="../search.html" method="get"> <input placeholder="Quick search" 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> </div> <script type="text/javascript">$('.inline-search').show(0);</script> | </li> </ul> </div> <div class="footer"> © <a href="../copyright.html">Copyright</a> 2001-2023, Python Software Foundation. <br /> The Python Software Foundation is a non-profit corporation. <a href="https://www.python.org/psf/donations/">Please donate.</a> <br /> Last updated on Dec 18, 2023. <a href="../bugs.html">Found a bug</a>? <br /> Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.7.6. </div> </body> </html>