945 lines
75 KiB
HTML
945 lines
75 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="../">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<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.13.3 documentation</title><meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
|
||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
||
<link rel="stylesheet" type="text/css" href="../_static/pydoctheme.css?v=23252803" />
|
||
<link id="pygments_dark_css" media="(prefers-color-scheme: dark)" rel="stylesheet" type="text/css" href="../_static/pygments_dark.css?v=5349f25f" />
|
||
|
||
<script src="../_static/documentation_options.js?v=5d57ca2d"></script>
|
||
<script src="../_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
|
||
<script src="../_static/sidebar.js"></script>
|
||
|
||
<link rel="search" type="application/opensearchdescription+xml"
|
||
title="Search within Python 3.13.3 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="timer file descriptor HOWTO" href="timerfd.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/search-focus.js"></script>
|
||
<script type="text/javascript" src="../_static/themetoggle.js"></script>
|
||
<script type="text/javascript" src="../_static/rtd_switcher.js"></script>
|
||
<meta name="readthedocs-addons-api-version" content="1">
|
||
|
||
</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="Python 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><ul>
|
||
<li><a class="reference internal" href="#tp-traverse-in-python-3-8-and-lower"><code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code> in Python 3.8 and lower</a></li>
|
||
<li><a class="reference internal" href="#delegating-tp-traverse">Delegating <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code></a></li>
|
||
<li><a class="reference internal" href="#defining-tp-dealloc">Defining <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a></li>
|
||
<li><a class="reference internal" href="#not-overriding-tp-free">Not overriding <code class="docutils literal notranslate"><span class="pre">tp_free</span></code></a></li>
|
||
<li><a class="reference internal" href="#avoiding-pyobject-new">Avoiding <code class="docutils literal notranslate"><span class="pre">PyObject_New</span></code></a></li>
|
||
</ul>
|
||
</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="timerfd.html"
|
||
title="next chapter">timer file descriptor HOWTO</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">
|
||
<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="timerfd.html" title="timer file descriptor HOWTO"
|
||
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.13.3 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" id="search-box" />
|
||
<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="Link to this heading">¶</a></h1>
|
||
<aside 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>
|
||
</aside>
|
||
<section id="who-should-read-this">
|
||
<h2>Who should read this<a class="headerlink" href="#who-should-read-this" title="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="w"> </span><span class="nn">sys</span>
|
||
<span class="gp">>>> </span><span class="kn">import</span><span class="w"> </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="w"> </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="Link to this heading">¶</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="Link to this heading">¶</a></h2>
|
||
<section id="managing-global-state">
|
||
<h3>Managing Global State<a class="headerlink" href="#managing-global-state" title="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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 <code class="docutils literal notranslate"><span class="pre">Py_VISIT(Py_TYPE(self))</span></code>).</p></li>
|
||
</ul>
|
||
<p>Please refer to the documentation 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>The API for defining heap types grew organically, leaving it
|
||
somewhat awkward to use in its current state.
|
||
The following sections will guide you through common issues.</p>
|
||
<section id="tp-traverse-in-python-3-8-and-lower">
|
||
<h4><code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code> in Python 3.8 and lower<a class="headerlink" href="#tp-traverse-in-python-3-8-and-lower" title="Link to this heading">¶</a></h4>
|
||
<p>The requirement to visit the type from <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code> was added in Python 3.9.
|
||
If you support Python 3.8 and lower, the traverse function must <em>not</em>
|
||
visit the type, so it must be more complicated:</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="nf">my_traverse</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">visitproc</span><span class="w"> </span><span class="n">visit</span><span class="p">,</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</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">Py_Version</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mh">0x03090000</span><span class="p">)</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="w"> </span><span class="p">}</span>
|
||
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Unfortunately, <a class="reference internal" href="../c-api/apiabiversion.html#c.Py_Version" title="Py_Version"><code class="xref c c-data docutils literal notranslate"><span class="pre">Py_Version</span></code></a> was only added in Python 3.11.
|
||
As a replacement, use:</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="../c-api/apiabiversion.html#c.PY_VERSION_HEX" title="PY_VERSION_HEX"><code class="xref c c-macro docutils literal notranslate"><span class="pre">PY_VERSION_HEX</span></code></a>, if not using the stable ABI, or</p></li>
|
||
<li><p><a class="reference internal" href="../library/sys.html#sys.version_info" title="sys.version_info"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.version_info</span></code></a> (via <a class="reference internal" href="../c-api/sys.html#c.PySys_GetObject" title="PySys_GetObject"><code class="xref c c-func docutils literal notranslate"><span class="pre">PySys_GetObject()</span></code></a> and
|
||
<a class="reference internal" href="../c-api/arg.html#c.PyArg_ParseTuple" title="PyArg_ParseTuple"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyArg_ParseTuple()</span></code></a>).</p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="delegating-tp-traverse">
|
||
<h4>Delegating <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code><a class="headerlink" href="#delegating-tp-traverse" title="Link to this heading">¶</a></h4>
|
||
<p>If your traverse function delegates to 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>
|
||
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="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">Py_Version</span><span class="w"> </span><span class="o">>=</span><span class="w"> </span><span class="mh">0x03090000</span><span class="p">)</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="w"> </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
|
||
<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_clear" title="PyTypeObject.tp_clear"><code class="xref c c-member docutils literal notranslate"><span class="pre">tp_clear</span></code></a>.</p>
|
||
</section>
|
||
<section id="defining-tp-dealloc">
|
||
<h4>Defining <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code><a class="headerlink" href="#defining-tp-dealloc" title="Link to this heading">¶</a></h4>
|
||
<p>If your type has a custom <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> function,
|
||
it needs to:</p>
|
||
<ul class="simple">
|
||
<li><p>call <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 any fields are invalidated, and</p></li>
|
||
<li><p>decrement the reference count of the type.</p></li>
|
||
</ul>
|
||
<p>To keep the type valid while <code class="docutils literal notranslate"><span class="pre">tp_free</span></code> is called, the type’s refcount needs
|
||
to be decremented <em>after</em> the instance is deallocated. 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">void</span><span class="w"> </span><span class="nf">my_dealloc</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="p">{</span>
|
||
<span class="w"> </span><span class="n">PyObject_GC_UnTrack</span><span class="p">(</span><span class="n">self</span><span class="p">);</span>
|
||
<span class="w"> </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">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </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="n">type</span><span class="o">-></span><span class="n">tp_free</span><span class="p">(</span><span class="n">self</span><span class="p">);</span>
|
||
<span class="w"> </span><span class="n">Py_DECREF</span><span class="p">(</span><span class="n">type</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The default <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code> function does this, so
|
||
if your type does <em>not</em> override
|
||
<code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code> you don’t need to add it.</p>
|
||
</section>
|
||
<section id="not-overriding-tp-free">
|
||
<h4>Not overriding <code class="docutils literal notranslate"><span class="pre">tp_free</span></code><a class="headerlink" href="#not-overriding-tp-free" title="Link to this heading">¶</a></h4>
|
||
<p>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> slot of a heap type must be set to
|
||
<a class="reference internal" href="../c-api/gcsupport.html#c.PyObject_GC_Del" title="PyObject_GC_Del"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GC_Del()</span></code></a>.
|
||
This is the default; do not override it.</p>
|
||
</section>
|
||
<section id="avoiding-pyobject-new">
|
||
<h4>Avoiding <code class="docutils literal notranslate"><span class="pre">PyObject_New</span></code><a class="headerlink" href="#avoiding-pyobject-new" title="Link to this heading">¶</a></h4>
|
||
<p>GC-tracked objects need to be allocated using GC-aware functions.</p>
|
||
<p>If you use use <a class="reference internal" href="../c-api/allocation.html#c.PyObject_New" title="PyObject_New"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_New()</span></code></a> or <a class="reference internal" href="../c-api/allocation.html#c.PyObject_NewVar" title="PyObject_NewVar"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_NewVar()</span></code></a>:</p>
|
||
<ul>
|
||
<li><p>Get and call type’s <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, if possible.
|
||
That is, replace <code class="docutils literal notranslate"><span class="pre">TYPE</span> <span class="pre">*o</span> <span class="pre">=</span> <span class="pre">PyObject_New(TYPE,</span> <span class="pre">typeobj)</span></code> with:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">TYPE</span><span class="w"> </span><span class="o">*</span><span class="n">o</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">typeobj</span><span class="o">-></span><span class="n">tp_alloc</span><span class="p">(</span><span class="n">typeobj</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Replace <code class="docutils literal notranslate"><span class="pre">o</span> <span class="pre">=</span> <span class="pre">PyObject_NewVar(TYPE,</span> <span class="pre">typeobj,</span> <span class="pre">size)</span></code> with the same,
|
||
but use size instead of the 0.</p>
|
||
</li>
|
||
<li><p>If the above is not possible (e.g. inside a custom <code class="docutils literal notranslate"><span class="pre">tp_alloc</span></code>),
|
||
call <a class="reference internal" href="../c-api/gcsupport.html#c.PyObject_GC_New" title="PyObject_GC_New"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GC_New()</span></code></a> or <a class="reference internal" href="../c-api/gcsupport.html#c.PyObject_GC_NewVar" title="PyObject_GC_NewVar"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyObject_GC_NewVar()</span></code></a>:</p>
|
||
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="n">TYPE</span><span class="w"> </span><span class="o">*</span><span class="n">o</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_GC_New</span><span class="p">(</span><span class="n">TYPE</span><span class="p">,</span><span class="w"> </span><span class="n">typeobj</span><span class="p">);</span>
|
||
|
||
<span class="n">TYPE</span><span class="w"> </span><span class="o">*</span><span class="n">o</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyObject_GC_NewVar</span><span class="p">(</span><span class="n">TYPE</span><span class="p">,</span><span class="w"> </span><span class="n">typeobj</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">);</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
<section id="module-state-access-from-classes">
|
||
<h3>Module State Access from Classes<a class="headerlink" href="#module-state-access-from-classes" title="Link to this heading">¶</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="Link to this heading">¶</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 <code class="docutils literal notranslate"><span class="pre">Py_TYPE(self)</span></code>. 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="w"> </span><span class="nc">Base</span><span class="p">:</span>
|
||
<span class="k">def</span><span class="w"> </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="w"> </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="w"> </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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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="Link to this heading">¶</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">
|
||
<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><ul>
|
||
<li><a class="reference internal" href="#tp-traverse-in-python-3-8-and-lower"><code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code> in Python 3.8 and lower</a></li>
|
||
<li><a class="reference internal" href="#delegating-tp-traverse">Delegating <code class="docutils literal notranslate"><span class="pre">tp_traverse</span></code></a></li>
|
||
<li><a class="reference internal" href="#defining-tp-dealloc">Defining <code class="docutils literal notranslate"><span class="pre">tp_dealloc</span></code></a></li>
|
||
<li><a class="reference internal" href="#not-overriding-tp-free">Not overriding <code class="docutils literal notranslate"><span class="pre">tp_free</span></code></a></li>
|
||
<li><a class="reference internal" href="#avoiding-pyobject-new">Avoiding <code class="docutils literal notranslate"><span class="pre">PyObject_New</span></code></a></li>
|
||
</ul>
|
||
</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="timerfd.html"
|
||
title="next chapter">timer file descriptor HOWTO</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 id="sidebarbutton" title="Collapse sidebar">
|
||
<span>«</span>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="Related">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="timerfd.html" title="timer file descriptor HOWTO"
|
||
>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.13.3 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" id="search-box" />
|
||
<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-2025, 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 Apr 08, 2025 (14:33 UTC).
|
||
|
||
<a href="/bugs.html">Found a bug</a>?
|
||
|
||
<br />
|
||
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 8.2.3.
|
||
</div>
|
||
|
||
</body>
|
||
</html> |