123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831 |
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
- <meta property="og:title" content="Isolating Extension Modules" />
- <meta property="og:type" content="website" />
- <meta property="og:url" content="https://docs.python.org/3/howto/isolating-extensions.html" />
- <meta property="og:site_name" content="Python documentation" />
- <meta property="og:description" content="Abstract: Traditionally, state belonging to Python extension modules was kept in C static variables, which have process-wide scope. This document describes problems of such per-process state and sh..." />
- <meta property="og:image" content="https://docs.python.org/3/_static/og-image.png" />
- <meta property="og:image:alt" content="Python documentation" />
- <meta name="description" content="Abstract: Traditionally, state belonging to Python extension modules was kept in C static variables, which have process-wide scope. This document describes problems of such per-process state and sh..." />
- <meta property="og:image:width" content="200" />
- <meta property="og:image:height" content="200" />
- <meta name="theme-color" content="#3776ab" />
- <title>Isolating Extension Modules — Python 3.12.0 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
-
- <link rel="stylesheet" type="text/css" href="../_static/pygments.css" />
- <link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?digest=b37c26da2f7529d09fe70b41c4b2133fe4931a90" />
- <link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css" />
-
- <script data-url_root="../" id="documentation_options" src="../_static/documentation_options.js"></script>
- <script src="../_static/jquery.js"></script>
- <script src="../_static/underscore.js"></script>
- <script src="../_static/doctools.js"></script>
-
- <script src="../_static/sidebar.js"></script>
-
- <link rel="search" type="application/opensearchdescription+xml"
- title="Search within Python 3.12.0 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="Python Frequently Asked Questions" href="../faq/index.html" />
- <link rel="prev" title="Annotations Best Practices" href="annotations.html" />
- <link rel="canonical" href="https://docs.python.org/3/howto/isolating-extensions.html" />
-
-
-
-
- <style>
- @media only screen {
- table.full-width-table {
- width: 100%;
- }
- }
- </style>
- <link rel="stylesheet" href="../_static/pydoctheme_dark.css" media="(prefers-color-scheme: dark)" id="pydoctheme_dark_css">
- <link rel="shortcut icon" type="image/png" href="../_static/py.svg" />
- <script type="text/javascript" src="../_static/copybutton.js"></script>
- <script type="text/javascript" src="../_static/menu.js"></script>
- <script type="text/javascript" src="../_static/themetoggle.js"></script>
- </head>
- <body>
- <div class="mobile-nav">
- <input type="checkbox" id="menuToggler" class="toggler__input" aria-controls="navigation"
- aria-pressed="false" aria-expanded="false" role="button" aria-label="Menu" />
- <nav class="nav-content" role="navigation">
- <label for="menuToggler" class="toggler__label">
- <span></span>
- </label>
- <span class="nav-items-wrapper">
- <a href="https://www.python.org/" class="nav-logo">
- <img src="../_static/py.svg" alt="Logo"/>
- </a>
- <span class="version_switcher_placeholder"></span>
- <form role="search" class="search" action="../search.html" method="get">
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" class="search-icon">
- <path fill-rule="nonzero" fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 001.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 00-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 005.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0 .41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
- </svg>
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go"/>
- </form>
- </span>
- </nav>
- <div class="menu-wrapper">
- <nav class="menu" role="navigation" aria-label="main navigation">
- <div class="language_switcher_placeholder"></div>
-
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label>
- <div>
- <h3><a href="../contents.html">Table of Contents</a></h3>
- <ul>
- <li><a class="reference internal" href="#">Isolating Extension Modules</a><ul>
- <li><a class="reference internal" href="#who-should-read-this">Who should read this</a></li>
- <li><a class="reference internal" href="#background">Background</a><ul>
- <li><a class="reference internal" href="#enter-per-module-state">Enter Per-Module State</a></li>
- <li><a class="reference internal" href="#isolated-module-objects">Isolated Module Objects</a></li>
- <li><a class="reference internal" href="#surprising-edge-cases">Surprising Edge Cases</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#making-modules-safe-with-multiple-interpreters">Making Modules Safe with Multiple Interpreters</a><ul>
- <li><a class="reference internal" href="#managing-global-state">Managing Global State</a></li>
- <li><a class="reference internal" href="#managing-per-module-state">Managing Per-Module State</a></li>
- <li><a class="reference internal" href="#opt-out-limiting-to-one-module-object-per-process">Opt-Out: Limiting to One Module Object per Process</a></li>
- <li><a class="reference internal" href="#module-state-access-from-functions">Module State Access from Functions</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#heap-types">Heap Types</a><ul>
- <li><a class="reference internal" href="#changing-static-types-to-heap-types">Changing Static Types to Heap Types</a></li>
- <li><a class="reference internal" href="#defining-heap-types">Defining Heap Types</a></li>
- <li><a class="reference internal" href="#garbage-collection-protocol">Garbage-Collection Protocol</a></li>
- <li><a class="reference internal" href="#module-state-access-from-classes">Module State Access from Classes</a></li>
- <li><a class="reference internal" href="#module-state-access-from-regular-methods">Module State Access from Regular Methods</a></li>
- <li><a class="reference internal" href="#module-state-access-from-slot-methods-getters-and-setters">Module State Access from Slot Methods, Getters and Setters</a></li>
- <li><a class="reference internal" href="#lifetime-of-the-module-state">Lifetime of the Module State</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
- <li><a class="reference internal" href="#per-class-scope">Per-Class Scope</a></li>
- <li><a class="reference internal" href="#lossless-conversion-to-heap-types">Lossless Conversion to Heap Types</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div>
- <div>
- <h4>Previous topic</h4>
- <p class="topless"><a href="annotations.html"
- title="previous chapter">Annotations Best Practices</a></p>
- </div>
- <div>
- <h4>Next topic</h4>
- <p class="topless"><a href="../faq/index.html"
- title="next chapter">Python Frequently Asked Questions</a></p>
- </div>
- <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/main/Doc/howto/isolating-extensions.rst"
- rel="nofollow">Show Source
- </a>
- </li>
- </ul>
- </div>
- </nav>
- </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"
- 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="../faq/index.html" title="Python Frequently Asked Questions"
- accesskey="N">next</a> |</li>
- <li class="right" >
- <a href="annotations.html" title="Annotations Best Practices"
- accesskey="P">previous</a> |</li>
- <li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
- <li><a href="https://www.python.org/">Python</a> »</li>
- <li class="switchers">
- <div class="language_switcher_placeholder"></div>
- <div class="version_switcher_placeholder"></div>
- </li>
- <li>
-
- </li>
- <li id="cpython-language-and-version">
- <a href="../index.html">3.12.0 Documentation</a> »
- </li>
- <li class="nav-item nav-item-1"><a href="index.html" accesskey="U">Python HOWTOs</a> »</li>
- <li class="nav-item nav-item-this"><a href="">Isolating Extension Modules</a></li>
- <li class="right">
-
- <div class="inline-search" role="search">
- <form class="inline-search" action="../search.html" method="get">
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go" />
- </form>
- </div>
- |
- </li>
- <li class="right">
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label> |</li>
-
- </ul>
- </div>
- <div class="document">
- <div class="documentwrapper">
- <div class="bodywrapper">
- <div class="body" role="main">
-
- <section id="isolating-extension-modules">
- <span id="isolating-extensions-howto"></span><h1>Isolating Extension Modules<a class="headerlink" href="#isolating-extension-modules" title="Permalink to this headline">¶</a></h1>
- <div class="topic">
- <p class="topic-title">Abstract</p>
- <p>Traditionally, state belonging to Python extension modules was kept in C
- <code class="docutils literal notranslate"><span class="pre">static</span></code> variables, which have process-wide scope. This document
- describes problems of such per-process state and shows a safer way:
- per-module state.</p>
- <p>The document also describes how to switch to per-module state where
- possible. This transition involves allocating space for that state, potentially
- switching from static types to heap types, and—perhaps most
- importantly—accessing per-module state from code.</p>
- </div>
- <section id="who-should-read-this">
- <h2>Who should read this<a class="headerlink" href="#who-should-read-this" title="Permalink to this headline">¶</a></h2>
- <p>This guide is written for maintainers of <a class="reference internal" href="../c-api/index.html#c-api-index"><span class="std std-ref">C-API</span></a> extensions
- who would like to make that extension safer to use in applications where
- Python itself is used as a library.</p>
- </section>
- <section id="background">
- <h2>Background<a class="headerlink" href="#background" title="Permalink to this headline">¶</a></h2>
- <p>An <em>interpreter</em> is the context in which Python code runs. It contains
- configuration (e.g. the import path) and runtime state (e.g. the set of
- imported modules).</p>
- <p>Python supports running multiple interpreters in one process. There are
- two cases to think about—users may run interpreters:</p>
- <ul class="simple">
- <li><p>in sequence, with several <a class="reference internal" href="../c-api/init.html#c.Py_InitializeEx" title="Py_InitializeEx"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_InitializeEx()</span></code></a>/<a class="reference internal" href="../c-api/init.html#c.Py_FinalizeEx" title="Py_FinalizeEx"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_FinalizeEx()</span></code></a>
- cycles, and</p></li>
- <li><p>in parallel, managing “sub-interpreters” using
- <a class="reference internal" href="../c-api/init.html#c.Py_NewInterpreter" title="Py_NewInterpreter"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_NewInterpreter()</span></code></a>/<a class="reference internal" href="../c-api/init.html#c.Py_EndInterpreter" title="Py_EndInterpreter"><code class="xref c c-func docutils literal notranslate"><span class="pre">Py_EndInterpreter()</span></code></a>.</p></li>
- </ul>
- <p>Both cases (and combinations of them) would be most useful when
- embedding Python within a library. Libraries generally shouldn’t make
- assumptions about the application that uses them, which include
- assuming a process-wide “main Python interpreter”.</p>
- <p>Historically, Python extension modules don’t handle this use case well.
- Many extension modules (and even some stdlib modules) use <em>per-process</em>
- global state, because C <code class="docutils literal notranslate"><span class="pre">static</span></code> variables are extremely easy to use.
- Thus, data that should be specific to an interpreter ends up being shared
- between interpreters. Unless the extension developer is careful, it is very
- easy to introduce edge cases that lead to crashes when a module is loaded in
- more than one interpreter in the same process.</p>
- <p>Unfortunately, <em>per-interpreter</em> state is not easy to achieve. Extension
- authors tend to not keep multiple interpreters in mind when developing,
- and it is currently cumbersome to test the behavior.</p>
- <section id="enter-per-module-state">
- <h3>Enter Per-Module State<a class="headerlink" href="#enter-per-module-state" title="Permalink to this headline">¶</a></h3>
- <p>Instead of focusing on per-interpreter state, Python’s C API is evolving
- to better support the more granular <em>per-module</em> state.
- This means that C-level data should be attached to a <em>module object</em>.
- Each interpreter creates its own module object, keeping the data separate.
- For testing the isolation, multiple module objects corresponding to a single
- extension can even be loaded in a single interpreter.</p>
- <p>Per-module state provides an easy way to think about lifetime and
- resource ownership: the extension module will initialize when a
- module object is created, and clean up when it’s freed. In this regard,
- a module is just like any other <span class="c-expr sig sig-inline c"><a class="reference internal" href="../c-api/structures.html#c.PyObject" title="PyObject"><span class="n">PyObject</span></a><span class="p">*</span></span>; there are no “on
- interpreter shutdown” hooks to think—or forget—about.</p>
- <p>Note that there are use cases for different kinds of “globals”:
- per-process, per-interpreter, per-thread or per-task state.
- With per-module state as the default, these are still possible,
- but you should treat them as exceptional cases:
- if you need them, you should give them additional care and testing.
- (Note that this guide does not cover them.)</p>
- </section>
- <section id="isolated-module-objects">
- <h3>Isolated Module Objects<a class="headerlink" href="#isolated-module-objects" title="Permalink to this headline">¶</a></h3>
- <p>The key point to keep in mind when developing an extension module is
- that several module objects can be created from a single shared library.
- For example:</p>
- <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="kn">import</span> <span class="nn">sys</span>
- <span class="gp">>>> </span><span class="kn">import</span> <span class="nn">binascii</span>
- <span class="gp">>>> </span><span class="n">old_binascii</span> <span class="o">=</span> <span class="n">binascii</span>
- <span class="gp">>>> </span><span class="k">del</span> <span class="n">sys</span><span class="o">.</span><span class="n">modules</span><span class="p">[</span><span class="s1">'binascii'</span><span class="p">]</span>
- <span class="gp">>>> </span><span class="kn">import</span> <span class="nn">binascii</span> <span class="c1"># create a new module object</span>
- <span class="gp">>>> </span><span class="n">old_binascii</span> <span class="o">==</span> <span class="n">binascii</span>
- <span class="go">False</span>
- </pre></div>
- </div>
- <p>As a rule of thumb, the two modules should be completely independent.
- All objects and state specific to the module should be encapsulated
- within the module object, not shared with other module objects, and
- cleaned up when the module object is deallocated.
- Since this just is a rule of thumb, exceptions are possible
- (see <a class="reference internal" href="#managing-global-state">Managing Global State</a>), but they will need more
- thought and attention to edge cases.</p>
- <p>While some modules could do with less stringent restrictions, isolated
- modules make it easier to set clear expectations and guidelines that
- work across a variety of use cases.</p>
- </section>
- <section id="surprising-edge-cases">
- <h3>Surprising Edge Cases<a class="headerlink" href="#surprising-edge-cases" title="Permalink to this headline">¶</a></h3>
- <p>Note that isolated modules do create some surprising edge cases. Most
- notably, each module object will typically not share its classes and
- exceptions with other similar modules. Continuing from the
- <a class="reference internal" href="#isolated-module-objects">example above</a>,
- note that <code class="docutils literal notranslate"><span class="pre">old_binascii.Error</span></code> and <code class="docutils literal notranslate"><span class="pre">binascii.Error</span></code> are
- separate objects. In the following code, the exception is <em>not</em> caught:</p>
- <div class="highlight-pycon notranslate"><div class="highlight"><pre><span></span><span class="gp">>>> </span><span class="n">old_binascii</span><span class="o">.</span><span class="n">Error</span> <span class="o">==</span> <span class="n">binascii</span><span class="o">.</span><span class="n">Error</span>
- <span class="go">False</span>
- <span class="gp">>>> </span><span class="k">try</span><span class="p">:</span>
- <span class="gp">... </span> <span class="n">old_binascii</span><span class="o">.</span><span class="n">unhexlify</span><span class="p">(</span><span class="sa">b</span><span class="s1">'qwertyuiop'</span><span class="p">)</span>
- <span class="gp">... </span><span class="k">except</span> <span class="n">binascii</span><span class="o">.</span><span class="n">Error</span><span class="p">:</span>
- <span class="gp">... </span> <span class="nb">print</span><span class="p">(</span><span class="s1">'boo'</span><span class="p">)</span>
- <span class="gp">...</span>
- <span class="gt">Traceback (most recent call last):</span>
- File <span class="nb">"<stdin>"</span>, line <span class="m">2</span>, in <span class="n"><module></span>
- <span class="gr">binascii.Error</span>: <span class="n">Non-hexadecimal digit found</span>
- </pre></div>
- </div>
- <p>This is expected. Notice that pure-Python modules behave the same way:
- it is a part of how Python works.</p>
- <p>The goal is to make extension modules safe at the C level, not to make
- hacks behave intuitively. Mutating <code class="docutils literal notranslate"><span class="pre">sys.modules</span></code> “manually” counts
- as a hack.</p>
- </section>
- </section>
- <section id="making-modules-safe-with-multiple-interpreters">
- <h2>Making Modules Safe with Multiple Interpreters<a class="headerlink" href="#making-modules-safe-with-multiple-interpreters" title="Permalink to this headline">¶</a></h2>
- <section id="managing-global-state">
- <h3>Managing Global State<a class="headerlink" href="#managing-global-state" title="Permalink to this headline">¶</a></h3>
- <p>Sometimes, the state associated with a Python module is not specific to that module, but
- to the entire process (or something else “more global” than a module).
- For example:</p>
- <ul class="simple">
- <li><p>The <code class="docutils literal notranslate"><span class="pre">readline</span></code> module manages <em>the</em> terminal.</p></li>
- <li><p>A module running on a circuit board wants to control <em>the</em> on-board
- LED.</p></li>
- </ul>
- <p>In these cases, the Python module should provide <em>access</em> to the global
- state, rather than <em>own</em> it. If possible, write the module so that
- multiple copies of it can access the state independently (along with
- other libraries, whether for Python or other languages). If that is not
- possible, consider explicit locking.</p>
- <p>If it is necessary to use process-global state, the simplest way to
- avoid issues with multiple interpreters is to explicitly prevent a
- module from being loaded more than once per process—see
- <a class="reference internal" href="#opt-out-limiting-to-one-module-object-per-process">Opt-Out: Limiting to One Module Object per Process</a>.</p>
- </section>
- <section id="managing-per-module-state">
- <h3>Managing Per-Module State<a class="headerlink" href="#managing-per-module-state" title="Permalink to this headline">¶</a></h3>
- <p>To use per-module state, use
- <a class="reference internal" href="../c-api/module.html#multi-phase-initialization"><span class="std std-ref">multi-phase extension module initialization</span></a>.
- This signals that your module supports multiple interpreters correctly.</p>
- <p>Set <code class="docutils literal notranslate"><span class="pre">PyModuleDef.m_size</span></code> to a positive number to request that many
- bytes of storage local to the module. Usually, this will be set to the
- size of some module-specific <code class="docutils literal notranslate"><span class="pre">struct</span></code>, which can store all of the
- module’s C-level state. In particular, it is where you should put
- pointers to classes (including exceptions, but excluding static types)
- and settings (e.g. <code class="docutils literal notranslate"><span class="pre">csv</span></code>’s <a class="reference internal" href="../library/csv.html#csv.field_size_limit" title="csv.field_size_limit"><code class="xref py py-data docutils literal notranslate"><span class="pre">field_size_limit</span></code></a>)
- which the C code needs to function.</p>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>Another option is to store state in the module’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>,
- but you must avoid crashing when users modify <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> from
- Python code. This usually means error- and type-checking at the C level,
- which is easy to get wrong and hard to test sufficiently.</p>
- <p>However, if module state is not needed in C code, storing it in
- <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> only is a good idea.</p>
- </div>
- <p>If the module state includes <code class="docutils literal notranslate"><span class="pre">PyObject</span></code> pointers, the module object
- must hold references to those objects and implement the module-level hooks
- <code class="docutils literal notranslate"><span class="pre">m_traverse</span></code>, <code class="docutils literal notranslate"><span class="pre">m_clear</span></code> and <code class="docutils literal notranslate"><span class="pre">m_free</span></code>. These work like
- <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code>, <code class="docutils literal notranslate"><span class="pre">tp_clear</span></code> and <code class="docutils literal notranslate"><span class="pre">tp_free</span></code> of a class. Adding them will
- require some work and make the code longer; this is the price for
- modules which can be unloaded cleanly.</p>
- <p>An example of a module with per-module state is currently available as
- <a class="reference external" href="https://github.com/python/cpython/blob/master/Modules/xxlimited.c">xxlimited</a>;
- example module initialization shown at the bottom of the file.</p>
- </section>
- <section id="opt-out-limiting-to-one-module-object-per-process">
- <h3>Opt-Out: Limiting to One Module Object per Process<a class="headerlink" href="#opt-out-limiting-to-one-module-object-per-process" title="Permalink to this headline">¶</a></h3>
- <p>A non-negative <code class="docutils literal notranslate"><span class="pre">PyModuleDef.m_size</span></code> signals that a module supports
- multiple interpreters correctly. If this is not yet the case for your
- module, you can explicitly make your module loadable only once per
- process. For example:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">loaded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
- <span class="k">static</span><span class="w"> </span><span class="kt">int</span>
- <span class="nf">exec_module</span><span class="p">(</span><span class="n">PyObject</span><span class="o">*</span><span class="w"> </span><span class="n">module</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">loaded</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="n">PyErr_SetString</span><span class="p">(</span><span class="n">PyExc_ImportError</span><span class="p">,</span>
- <span class="w"> </span><span class="s">"cannot load module more than once per process"</span><span class="p">);</span>
- <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">-1</span><span class="p">;</span>
- <span class="w"> </span><span class="p">}</span>
- <span class="w"> </span><span class="n">loaded</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
- <span class="w"> </span><span class="c1">// ... rest of initialization</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- </section>
- <section id="module-state-access-from-functions">
- <h3>Module State Access from Functions<a class="headerlink" href="#module-state-access-from-functions" title="Permalink to this headline">¶</a></h3>
- <p>Accessing the state from module-level functions is straightforward.
- Functions get the module object as their first argument; for extracting
- the state, you can use <code class="docutils literal notranslate"><span class="pre">PyModule_GetState</span></code>:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span>
- <span class="nf">func</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">module</span><span class="p">,</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">args</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="w"> </span><span class="n">my_struct</span><span class="w"> </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">my_struct</span><span class="o">*</span><span class="p">)</span><span class="n">PyModule_GetState</span><span class="p">(</span><span class="n">module</span><span class="p">);</span>
- <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">state</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
- <span class="w"> </span><span class="p">}</span>
- <span class="w"> </span><span class="c1">// ... rest of logic</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p><code class="docutils literal notranslate"><span class="pre">PyModule_GetState</span></code> may return <code class="docutils literal notranslate"><span class="pre">NULL</span></code> without setting an
- exception if there is no module state, i.e. <code class="docutils literal notranslate"><span class="pre">PyModuleDef.m_size</span></code> was
- zero. In your own module, you’re in control of <code class="docutils literal notranslate"><span class="pre">m_size</span></code>, so this is
- easy to prevent.</p>
- </div>
- </section>
- </section>
- <section id="heap-types">
- <h2>Heap Types<a class="headerlink" href="#heap-types" title="Permalink to this headline">¶</a></h2>
- <p>Traditionally, types defined in C code are <em>static</em>; that is,
- <code class="docutils literal notranslate"><span class="pre">static</span> <span class="pre">PyTypeObject</span></code> structures defined directly in code and
- initialized using <code class="docutils literal notranslate"><span class="pre">PyType_Ready()</span></code>.</p>
- <p>Such types are necessarily shared across the process. Sharing them
- between module objects requires paying attention to any state they own
- or access. To limit the possible issues, static types are immutable at
- the Python level: for example, you can’t set <code class="docutils literal notranslate"><span class="pre">str.myattribute</span> <span class="pre">=</span> <span class="pre">123</span></code>.</p>
- <div class="impl-detail compound">
- <p><strong>CPython implementation detail:</strong> Sharing truly immutable objects between interpreters is fine,
- as long as they don’t provide access to mutable objects.
- However, in CPython, every Python object has a mutable implementation
- detail: the reference count. Changes to the refcount are guarded by the GIL.
- Thus, code that shares any Python objects across interpreters implicitly
- depends on CPython’s current, process-wide GIL.</p>
- </div>
- <p>Because they are immutable and process-global, static types cannot access
- “their” module state.
- If any method of such a type requires access to module state,
- the type must be converted to a <em>heap-allocated type</em>, or <em>heap type</em>
- for short. These correspond more closely to classes created by Python’s
- <code class="docutils literal notranslate"><span class="pre">class</span></code> statement.</p>
- <p>For new modules, using heap types by default is a good rule of thumb.</p>
- <section id="changing-static-types-to-heap-types">
- <h3>Changing Static Types to Heap Types<a class="headerlink" href="#changing-static-types-to-heap-types" title="Permalink to this headline">¶</a></h3>
- <p>Static types can be converted to heap types, but note that
- the heap type API was not designed for “lossless” conversion
- from static types—that is, creating a type that works exactly like a given
- static type.
- So, when rewriting the class definition in a new API,
- you are likely to unintentionally change a few details (e.g. pickleability
- or inherited slots).
- Always test the details that are important to you.</p>
- <p>Watch out for the following two points in particular (but note that this is not
- a comprehensive list):</p>
- <ul class="simple">
- <li><p>Unlike static types, heap type objects are mutable by default.
- Use the <a class="reference internal" href="../c-api/typeobj.html#c.Py_TPFLAGS_IMMUTABLETYPE" title="Py_TPFLAGS_IMMUTABLETYPE"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TPFLAGS_IMMUTABLETYPE</span></code></a> flag to prevent mutability.</p></li>
- <li><p>Heap types inherit <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> by default,
- so it may become possible to instantiate them from Python code.
- You can prevent this with the <a class="reference internal" href="../c-api/typeobj.html#c.Py_TPFLAGS_DISALLOW_INSTANTIATION" title="Py_TPFLAGS_DISALLOW_INSTANTIATION"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TPFLAGS_DISALLOW_INSTANTIATION</span></code></a> flag.</p></li>
- </ul>
- </section>
- <section id="defining-heap-types">
- <h3>Defining Heap Types<a class="headerlink" href="#defining-heap-types" title="Permalink to this headline">¶</a></h3>
- <p>Heap types can be created by filling a <a class="reference internal" href="../c-api/type.html#c.PyType_Spec" title="PyType_Spec"><code class="xref c c-struct docutils literal notranslate"><span class="pre">PyType_Spec</span></code></a> structure, a
- description or “blueprint” of a class, and calling
- <a class="reference internal" href="../c-api/type.html#c.PyType_FromModuleAndSpec" title="PyType_FromModuleAndSpec"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_FromModuleAndSpec()</span></code></a> to construct a new class object.</p>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>Other functions, like <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>, can also create
- heap types, but <a class="reference internal" href="../c-api/type.html#c.PyType_FromModuleAndSpec" title="PyType_FromModuleAndSpec"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_FromModuleAndSpec()</span></code></a> associates the module
- with the class, allowing access to the module state from methods.</p>
- </div>
- <p>The class should generally be stored in <em>both</em> the module state (for
- safe access from C) and the module’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> (for access from
- Python code).</p>
- </section>
- <section id="garbage-collection-protocol">
- <h3>Garbage-Collection Protocol<a class="headerlink" href="#garbage-collection-protocol" title="Permalink to this headline">¶</a></h3>
- <p>Instances of heap types hold a reference to their type.
- This ensures that the type isn’t destroyed before all its instances are,
- but may result in reference cycles that need to be broken by the
- garbage collector.</p>
- <p>To avoid memory leaks, instances of heap types must implement the
- garbage collection protocol.
- That is, heap types should:</p>
- <ul class="simple">
- <li><p>Have the <a class="reference internal" href="../c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC" title="Py_TPFLAGS_HAVE_GC"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_GC</span></code></a> flag.</p></li>
- <li><p>Define a traverse function using <code class="docutils literal notranslate"><span class="pre">Py_tp_traverse</span></code>, which
- visits the type (e.g. using <span class="c-expr sig sig-inline c"><a class="reference internal" href="../c-api/gcsupport.html#c.Py_VISIT" title="Py_VISIT"><span class="n">Py_VISIT</span></a><span class="p">(</span><a class="reference internal" href="../c-api/structures.html#c.Py_TYPE" title="Py_TYPE"><span class="n">Py_TYPE</span></a><span class="p">(</span><span class="n">self</span><span class="p">)</span><span class="p">)</span></span>).</p></li>
- </ul>
- <p>Please refer to the <a class="reference internal" href="../c-api/typeobj.html#type-structs"><span class="std std-ref">the documentation</span></a> of
- <a class="reference internal" href="../c-api/typeobj.html#c.Py_TPFLAGS_HAVE_GC" title="Py_TPFLAGS_HAVE_GC"><code class="xref c c-macro docutils literal notranslate"><span class="pre">Py_TPFLAGS_HAVE_GC</span></code></a> and <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>
- for additional considerations.</p>
- <p>If your traverse function delegates to the <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code> of its base class
- (or another type), ensure that <code class="docutils literal notranslate"><span class="pre">Py_TYPE(self)</span></code> is visited only once.
- Note that only heap type are expected to visit the type in <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code>.</p>
- <p>For example, if your traverse function includes:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">base</span><span class="o">-></span><span class="n">tp_traverse</span><span class="p">(</span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="n">visit</span><span class="p">,</span><span class="w"> </span><span class="n">arg</span><span class="p">)</span>
- </pre></div>
- </div>
- <p>…and <code class="docutils literal notranslate"><span class="pre">base</span></code> may be a static type, then it should also include:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">base</span><span class="o">-></span><span class="n">tp_flags</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">Py_TPFLAGS_HEAPTYPE</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="c1">// a heap type's tp_traverse already visited Py_TYPE(self)</span>
- <span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="n">Py_VISIT</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="p">}</span>
- </pre></div>
- </div>
- <p>It is not necessary to handle the type’s reference count in <code class="docutils literal notranslate"><span class="pre">tp_new</span></code>
- and <code class="docutils literal notranslate"><span class="pre">tp_clear</span></code>.</p>
- </section>
- <section id="module-state-access-from-classes">
- <h3>Module State Access from Classes<a class="headerlink" href="#module-state-access-from-classes" title="Permalink to this headline">¶</a></h3>
- <p>If you have a type object defined with <a class="reference internal" href="../c-api/type.html#c.PyType_FromModuleAndSpec" title="PyType_FromModuleAndSpec"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_FromModuleAndSpec()</span></code></a>,
- you can call <a class="reference internal" href="../c-api/type.html#c.PyType_GetModule" title="PyType_GetModule"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModule()</span></code></a> to get the associated module, and then
- <a class="reference internal" href="../c-api/module.html#c.PyModule_GetState" title="PyModule_GetState"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyModule_GetState()</span></code></a> to get the module’s state.</p>
- <p>To save a some tedious error-handling boilerplate code, you can combine
- these two steps with <a class="reference internal" href="../c-api/type.html#c.PyType_GetModuleState" title="PyType_GetModuleState"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModuleState()</span></code></a>, resulting in:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">my_struct</span><span class="w"> </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">my_struct</span><span class="o">*</span><span class="p">)</span><span class="n">PyType_GetModuleState</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
- <span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">state</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- </section>
- <section id="module-state-access-from-regular-methods">
- <h3>Module State Access from Regular Methods<a class="headerlink" href="#module-state-access-from-regular-methods" title="Permalink to this headline">¶</a></h3>
- <p>Accessing the module-level state from methods of a class is somewhat more
- complicated, but is possible thanks to API introduced in Python 3.9.
- To get the state, you need to first get the <em>defining class</em>, and then
- get the module state from it.</p>
- <p>The largest roadblock is getting <em>the class a method was defined in</em>, or
- that method’s “defining class” for short. The defining class can have a
- reference to the module it is part of.</p>
- <p>Do not confuse the defining class with <span class="c-expr sig sig-inline c"><a class="reference internal" href="../c-api/structures.html#c.Py_TYPE" title="Py_TYPE"><span class="n">Py_TYPE</span></a><span class="p">(</span><span class="n">self</span><span class="p">)</span></span>. If the method
- is called on a <em>subclass</em> of your type, <code class="docutils literal notranslate"><span class="pre">Py_TYPE(self)</span></code> will refer to
- that subclass, which may be defined in different module than yours.</p>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>The following Python code can illustrate the concept.
- <code class="docutils literal notranslate"><span class="pre">Base.get_defining_class</span></code> returns <code class="docutils literal notranslate"><span class="pre">Base</span></code> even
- if <code class="docutils literal notranslate"><span class="pre">type(self)</span> <span class="pre">==</span> <span class="pre">Sub</span></code>:</p>
- <div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Base</span><span class="p">:</span>
- <span class="k">def</span> <span class="nf">get_type_of_self</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
- <span class="k">return</span> <span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
- <span class="k">def</span> <span class="nf">get_defining_class</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
- <span class="k">return</span> <span class="vm">__class__</span>
- <span class="k">class</span> <span class="nc">Sub</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span>
- <span class="k">pass</span>
- </pre></div>
- </div>
- </div>
- <p>For a method to get its “defining class”, it must use the
- <a class="reference internal" href="../c-api/structures.html#meth-method-meth-fastcall-meth-keywords"><span class="std std-ref">METH_METHOD | METH_FASTCALL | METH_KEYWORDS</span></a>
- <a class="reference internal" href="../c-api/structures.html#c.PyMethodDef" title="PyMethodDef"><code class="xref c c-type docutils literal notranslate"><span class="pre">calling</span> <span class="pre">convention</span></code></a>
- and the corresponding <a class="reference internal" href="../c-api/structures.html#c.PyCMethod" title="PyCMethod"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyCMethod</span></code></a> signature:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">PyCMethod</span><span class="p">(</span>
- <span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">,</span><span class="w"> </span><span class="c1">// object the method was called on</span>
- <span class="w"> </span><span class="n">PyTypeObject</span><span class="w"> </span><span class="o">*</span><span class="n">defining_class</span><span class="p">,</span><span class="w"> </span><span class="c1">// defining class</span>
- <span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="o">*</span><span class="n">args</span><span class="p">,</span><span class="w"> </span><span class="c1">// C array of arguments</span>
- <span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">nargs</span><span class="p">,</span><span class="w"> </span><span class="c1">// length of "args"</span>
- <span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">kwnames</span><span class="p">)</span><span class="w"> </span><span class="c1">// NULL, or dict of keyword arguments</span>
- </pre></div>
- </div>
- <p>Once you have the defining class, call <a class="reference internal" href="../c-api/type.html#c.PyType_GetModuleState" title="PyType_GetModuleState"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModuleState()</span></code></a> to get
- the state of its associated module.</p>
- <p>For example:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span>
- <span class="nf">example_method</span><span class="p">(</span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">self</span><span class="p">,</span>
- <span class="w"> </span><span class="n">PyTypeObject</span><span class="w"> </span><span class="o">*</span><span class="n">defining_class</span><span class="p">,</span>
- <span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="k">const</span><span class="w"> </span><span class="o">*</span><span class="n">args</span><span class="p">,</span>
- <span class="w"> </span><span class="n">Py_ssize_t</span><span class="w"> </span><span class="n">nargs</span><span class="p">,</span>
- <span class="w"> </span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">kwnames</span><span class="p">)</span>
- <span class="p">{</span>
- <span class="w"> </span><span class="n">my_struct</span><span class="w"> </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">my_struct</span><span class="o">*</span><span class="p">)</span><span class="n">PyType_GetModuleState</span><span class="p">(</span><span class="n">defining_class</span><span class="p">);</span>
- <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">state</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
- <span class="w"> </span><span class="p">}</span>
- <span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="c1">// rest of logic</span>
- <span class="p">}</span>
- <span class="n">PyDoc_STRVAR</span><span class="p">(</span><span class="n">example_method_doc</span><span class="p">,</span><span class="w"> </span><span class="s">"..."</span><span class="p">);</span>
- <span class="k">static</span><span class="w"> </span><span class="n">PyMethodDef</span><span class="w"> </span><span class="n">my_methods</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="p">{</span><span class="s">"example_method"</span><span class="p">,</span>
- <span class="w"> </span><span class="p">(</span><span class="n">PyCFunction</span><span class="p">)(</span><span class="kt">void</span><span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="kt">void</span><span class="p">))</span><span class="n">example_method</span><span class="p">,</span>
- <span class="w"> </span><span class="n">METH_METHOD</span><span class="o">|</span><span class="n">METH_FASTCALL</span><span class="o">|</span><span class="n">METH_KEYWORDS</span><span class="p">,</span>
- <span class="w"> </span><span class="n">example_method_doc</span><span class="p">}</span>
- <span class="w"> </span><span class="p">{</span><span class="nb">NULL</span><span class="p">},</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- </section>
- <section id="module-state-access-from-slot-methods-getters-and-setters">
- <h3>Module State Access from Slot Methods, Getters and Setters<a class="headerlink" href="#module-state-access-from-slot-methods-getters-and-setters" title="Permalink to this headline">¶</a></h3>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>This is new in Python 3.11.</p>
- </div>
- <p>Slot methods—the fast C equivalents for special methods, such as
- <a class="reference internal" href="../c-api/typeobj.html#c.PyNumberMethods.nb_add" title="PyNumberMethods.nb_add"><code class="xref c c-member docutils literal notranslate"><span class="pre">nb_add</span></code></a> for <a class="reference internal" href="../reference/datamodel.html#object.__add__" title="object.__add__"><code class="xref py py-attr docutils literal notranslate"><span class="pre">__add__</span></code></a> or
- <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> for initialization—have a very simple API that
- doesn’t allow passing in the defining class, unlike with <a class="reference internal" href="../c-api/structures.html#c.PyCMethod" title="PyCMethod"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyCMethod</span></code></a>.
- The same goes for getters and setters defined with
- <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>.</p>
- <p>To access the module state in these cases, use the
- <a class="reference internal" href="../c-api/type.html#c.PyType_GetModuleByDef" title="PyType_GetModuleByDef"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModuleByDef()</span></code></a> function, and pass in the module definition.
- Once you have the module, call <a class="reference internal" href="../c-api/module.html#c.PyModule_GetState" title="PyModule_GetState"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyModule_GetState()</span></code></a>
- to get the state:</p>
- <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">PyObject</span><span class="w"> </span><span class="o">*</span><span class="n">module</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyType_GetModuleByDef</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="w"> </span><span class="o">&</span><span class="n">module_def</span><span class="p">);</span>
- <span class="n">my_struct</span><span class="w"> </span><span class="o">*</span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">my_struct</span><span class="o">*</span><span class="p">)</span><span class="n">PyModule_GetState</span><span class="p">(</span><span class="n">module</span><span class="p">);</span>
- <span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">state</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nb">NULL</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
- <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">NULL</span><span class="p">;</span>
- <span class="p">}</span>
- </pre></div>
- </div>
- <p><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModuleByDef()</span></code> works by searching the
- <a class="reference internal" href="../glossary.html#term-method-resolution-order"><span class="xref std std-term">method resolution order</span></a> (i.e. all superclasses) for the first
- superclass that has a corresponding module.</p>
- <div class="admonition note">
- <p class="admonition-title">Note</p>
- <p>In very exotic cases (inheritance chains spanning multiple modules
- created from the same definition), <code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_GetModuleByDef()</span></code> might not
- return the module of the true defining class. However, it will always
- return a module with the same definition, ensuring a compatible
- C memory layout.</p>
- </div>
- </section>
- <section id="lifetime-of-the-module-state">
- <h3>Lifetime of the Module State<a class="headerlink" href="#lifetime-of-the-module-state" title="Permalink to this headline">¶</a></h3>
- <p>When a module object is garbage-collected, its module state is freed.
- For each pointer to (a part of) the module state, you must hold a reference
- to the module object.</p>
- <p>Usually this is not an issue, because types created with
- <a class="reference internal" href="../c-api/type.html#c.PyType_FromModuleAndSpec" title="PyType_FromModuleAndSpec"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyType_FromModuleAndSpec()</span></code></a>, and their instances, hold a reference
- to the module.
- However, you must be careful in reference counting when you reference
- module state from other places, such as callbacks for external
- libraries.</p>
- </section>
- </section>
- <section id="open-issues">
- <h2>Open Issues<a class="headerlink" href="#open-issues" title="Permalink to this headline">¶</a></h2>
- <p>Several issues around per-module state and heap types are still open.</p>
- <p>Discussions about improving the situation are best held on the <a class="reference external" href="https://mail.python.org/mailman3/lists/capi-sig.python.org/">capi-sig
- mailing list</a>.</p>
- <section id="per-class-scope">
- <h3>Per-Class Scope<a class="headerlink" href="#per-class-scope" title="Permalink to this headline">¶</a></h3>
- <p>It is currently (as of Python 3.11) not possible to attach state to individual
- <em>types</em> without relying on CPython implementation details (which may change
- in the future—perhaps, ironically, to allow a proper solution for
- per-class scope).</p>
- </section>
- <section id="lossless-conversion-to-heap-types">
- <h3>Lossless Conversion to Heap Types<a class="headerlink" href="#lossless-conversion-to-heap-types" title="Permalink to this headline">¶</a></h3>
- <p>The heap type API was not designed for “lossless” conversion from static types;
- that is, creating a type that works exactly like a given static type.</p>
- </section>
- </section>
- </section>
- <div class="clearer"></div>
- </div>
- </div>
- </div>
- <div class="sphinxsidebar" role="navigation" aria-label="main navigation">
- <div class="sphinxsidebarwrapper">
- <div>
- <h3><a href="../contents.html">Table of Contents</a></h3>
- <ul>
- <li><a class="reference internal" href="#">Isolating Extension Modules</a><ul>
- <li><a class="reference internal" href="#who-should-read-this">Who should read this</a></li>
- <li><a class="reference internal" href="#background">Background</a><ul>
- <li><a class="reference internal" href="#enter-per-module-state">Enter Per-Module State</a></li>
- <li><a class="reference internal" href="#isolated-module-objects">Isolated Module Objects</a></li>
- <li><a class="reference internal" href="#surprising-edge-cases">Surprising Edge Cases</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#making-modules-safe-with-multiple-interpreters">Making Modules Safe with Multiple Interpreters</a><ul>
- <li><a class="reference internal" href="#managing-global-state">Managing Global State</a></li>
- <li><a class="reference internal" href="#managing-per-module-state">Managing Per-Module State</a></li>
- <li><a class="reference internal" href="#opt-out-limiting-to-one-module-object-per-process">Opt-Out: Limiting to One Module Object per Process</a></li>
- <li><a class="reference internal" href="#module-state-access-from-functions">Module State Access from Functions</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#heap-types">Heap Types</a><ul>
- <li><a class="reference internal" href="#changing-static-types-to-heap-types">Changing Static Types to Heap Types</a></li>
- <li><a class="reference internal" href="#defining-heap-types">Defining Heap Types</a></li>
- <li><a class="reference internal" href="#garbage-collection-protocol">Garbage-Collection Protocol</a></li>
- <li><a class="reference internal" href="#module-state-access-from-classes">Module State Access from Classes</a></li>
- <li><a class="reference internal" href="#module-state-access-from-regular-methods">Module State Access from Regular Methods</a></li>
- <li><a class="reference internal" href="#module-state-access-from-slot-methods-getters-and-setters">Module State Access from Slot Methods, Getters and Setters</a></li>
- <li><a class="reference internal" href="#lifetime-of-the-module-state">Lifetime of the Module State</a></li>
- </ul>
- </li>
- <li><a class="reference internal" href="#open-issues">Open Issues</a><ul>
- <li><a class="reference internal" href="#per-class-scope">Per-Class Scope</a></li>
- <li><a class="reference internal" href="#lossless-conversion-to-heap-types">Lossless Conversion to Heap Types</a></li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </div>
- <div>
- <h4>Previous topic</h4>
- <p class="topless"><a href="annotations.html"
- title="previous chapter">Annotations Best Practices</a></p>
- </div>
- <div>
- <h4>Next topic</h4>
- <p class="topless"><a href="../faq/index.html"
- title="next chapter">Python Frequently Asked Questions</a></p>
- </div>
- <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/main/Doc/howto/isolating-extensions.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="../faq/index.html" title="Python Frequently Asked Questions"
- >next</a> |</li>
- <li class="right" >
- <a href="annotations.html" title="Annotations Best Practices"
- >previous</a> |</li>
- <li><img src="../_static/py.svg" alt="python logo" style="vertical-align: middle; margin-top: -1px"/></li>
- <li><a href="https://www.python.org/">Python</a> »</li>
- <li class="switchers">
- <div class="language_switcher_placeholder"></div>
- <div class="version_switcher_placeholder"></div>
- </li>
- <li>
-
- </li>
- <li id="cpython-language-and-version">
- <a href="../index.html">3.12.0 Documentation</a> »
- </li>
- <li class="nav-item nav-item-1"><a href="index.html" >Python HOWTOs</a> »</li>
- <li class="nav-item nav-item-this"><a href="">Isolating Extension Modules</a></li>
- <li class="right">
-
- <div class="inline-search" role="search">
- <form class="inline-search" action="../search.html" method="get">
- <input placeholder="Quick search" aria-label="Quick search" type="search" name="q" />
- <input type="submit" value="Go" />
- </form>
- </div>
- |
- </li>
- <li class="right">
- <label class="theme-selector-label">
- Theme
- <select class="theme-selector" oninput="activateTheme(this.value)">
- <option value="auto" selected>Auto</option>
- <option value="light">Light</option>
- <option value="dark">Dark</option>
- </select>
- </label> |</li>
-
- </ul>
- </div>
- <div class="footer">
- © <a href="../copyright.html">Copyright</a> 2001-2023, Python Software Foundation.
- <br />
- This page is licensed under the Python Software Foundation License Version 2.
- <br />
- Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License.
- <br />
- See <a href="/license.html">History and License</a> for more information.<br />
- <br />
- The Python Software Foundation is a non-profit corporation.
- <a href="https://www.python.org/psf/donations/">Please donate.</a>
- <br />
- <br />
- Last updated on Oct 02, 2023.
- <a href="/bugs.html">Found a bug</a>?
- <br />
- Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 4.5.0.
- </div>
- </body>
- </html>
|