CINXE.COM

PEP 757 – C API to import-export Python integers | peps.python.org

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 757 – C API to import-export Python integers | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0757/"> <link rel="stylesheet" href="../_static/style.css" type="text/css"> <link rel="stylesheet" href="../_static/mq.css" type="text/css"> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" media="(prefers-color-scheme: light)" id="pyg-light"> <link rel="stylesheet" href="../_static/pygments_dark.css" type="text/css" media="(prefers-color-scheme: dark)" id="pyg-dark"> <link rel="alternate" type="application/rss+xml" title="Latest PEPs" href="https://peps.python.org/peps.rss"> <meta property="og:title" content='PEP 757 – C API to import-export Python integers | peps.python.org'> <meta property="og:description" content="Add a new C API to import and export Python integers, int objects: especially PyLongWriter_Create() and PyLong_Export() functions."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0757/"> <meta property="og:site_name" content="Python Enhancement Proposals (PEPs)"> <meta property="og:image" content="https://peps.python.org/_static/og-image.png"> <meta property="og:image:alt" content="Python PEPs"> <meta property="og:image:width" content="200"> <meta property="og:image:height" content="200"> <meta name="description" content="Add a new C API to import and export Python integers, int objects: especially PyLongWriter_Create() and PyLong_Export() functions."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> &raquo; </li> <li><a href="../pep-0000/">PEP Index</a> &raquo; </li> <li>PEP 757</li> </ul> <button id="colour-scheme-cycler" onClick="setColourScheme(nextColourScheme())"> <svg aria-hidden="true" class="colour-scheme-icon-when-auto"><use href="#svg-sun-half"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-dark"><use href="#svg-moon"></use></svg> <svg aria-hidden="true" class="colour-scheme-icon-when-light"><use href="#svg-sun"></use></svg> <span class="visually-hidden">Toggle light / dark / auto colour theme</span> </button> </header> <article> <section id="pep-content"> <h1 class="page-title">PEP 757 – C API to import-export Python integers</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Sergey B Kirpichev &lt;skirpichev&#32;&#97;t&#32;gmail.com&gt;, Victor Stinner &lt;vstinner&#32;&#97;t&#32;python.org&gt;</dd> <dt class="field-even">Discussions-To<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/63895">Discourse thread</a></dd> <dt class="field-odd">Status<span class="colon">:</span></dt> <dd class="field-odd"><abbr title="Accepted and implementation complete, or no longer active">Final</abbr></dd> <dt class="field-even">Type<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Normative PEP with a new feature for Python, implementation change for CPython or interoperability standard for the ecosystem">Standards Track</abbr></dd> <dt class="field-odd">Created<span class="colon">:</span></dt> <dd class="field-odd">13-Sep-2024</dd> <dt class="field-even">Python-Version<span class="colon">:</span></dt> <dd class="field-even">3.14</dd> <dt class="field-odd">Post-History<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://discuss.python.org/t/63895" title="Discourse thread">14-Sep-2024</a></dd> <dt class="field-even">Resolution<span class="colon">:</span></dt> <dd class="field-even"><a class="reference external" href="https://discuss.python.org/t/63895/79">08-Dec-2024</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#layout-api">Layout API</a></li> <li><a class="reference internal" href="#id1">Export API</a></li> <li><a class="reference internal" href="#import-api">Import API</a></li> </ul> </li> <li><a class="reference internal" href="#optimize-import-for-small-integers">Optimize import for small integers</a></li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#benchmarks">Benchmarks</a><ul> <li><a class="reference internal" href="#export-pylong-export-with-gmpy2">Export: <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a> with gmpy2</a></li> <li><a class="reference internal" href="#import-pylongwriter-create-with-gmpy2">Import: <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a> with gmpy2</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#support-arbitrary-layout">Support arbitrary layout</a></li> <li><a class="reference internal" href="#don-t-add-pylong-getnativelayout-function">Don’t add <a class="reference internal" href="#c.PyLong_GetNativeLayout" title="PyLong_GetNativeLayout"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetNativeLayout()</span></code></a> function</a></li> <li><a class="reference internal" href="#provide-mpz-import-export-like-api-instead">Provide mpz_import/export-like API instead</a></li> <li><a class="reference internal" href="#drop-value-field-from-the-export-api">Drop <a class="reference internal" href="#c.PyLongExport.value" title="PyLongExport.value"><code class="xref c c-member docutils literal notranslate"><span class="pre">value</span></code></a> field from the export API</a></li> </ul> </li> <li><a class="reference internal" href="#discussions">Discussions</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <div class="pep-banner canonical-doc sticky-banner admonition important"> <p class="admonition-title">Important</p> <p>This PEP is a historical document. The up-to-date, canonical documentation can now be found at the <a class="reference external" href="https://docs.python.org/dev/c-api/long.html#export-api">Export API</a> and the <a class="reference external" href="https://docs.python.org/dev/c-api/long.html#pylongwriter-api">PyLongWriter API</a>.</p> <p class="close-button">×</p> <p>See <a class="pep reference internal" href="../pep-0001/" title="PEP 1 – PEP Purpose and Guidelines">PEP 1</a> for how to propose changes.</p> </div> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>Add a new C API to import and export Python integers, <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> objects: especially <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a> and <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a> functions.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Projects such as <a class="reference external" href="https://github.com/aleaxit/gmpy">gmpy2</a>, <a class="reference external" href="https://www.sagemath.org/">SAGE</a> and <a class="reference external" href="https://github.com/flintlib/python-flint">Python-FLINT</a> access directly Python “internals” (the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLongObject" title="(in Python v3.13)"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongObject</span></code></a> structure) or use an inefficient temporary format (hex strings for Python-FLINT) to import and export Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> objects. The Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> implementation changed in Python 3.12 to add a tag and “compact values”.</p> <p>In the 3.13 alpha 1 release, the private undocumented <code class="xref c c-func docutils literal notranslate"><span class="pre">_PyLong_New()</span></code> function had been removed, but it is being used by these projects to import Python integers. The private function has been restored in 3.13 alpha 2.</p> <p>A public efficient abstraction is needed to interface Python with these projects without exposing implementation details. It would allow Python to change its internals without breaking these projects. For example, implementation for gmpy2 was changed recently for CPython 3.9 and for CPython 3.12.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <section id="layout-api"> <h3><a class="toc-backref" href="#layout-api" role="doc-backlink">Layout API</a></h3> <p>Data needed by <a class="reference external" href="https://gmplib.org/">GMP</a>-like <a class="reference external" href="https://gmplib.org/manual/Integer-Import-and-Export#index-mpz_005fimport">import</a>-<a class="reference external" href="https://gmplib.org/manual/Integer-Import-and-Export#index-mpz_005fexport">export</a> functions.</p> <dl class="c struct"> <dt class="sig sig-object c" id="c.PyLongLayout"> <span class="k"><span class="pre">struct</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLongLayout</span></span></span><br /></dt> <dd>Layout of an array of “digits” (“limbs” in the GMP terminology), used to represent absolute value for arbitrary precision integers.<p>Use <a class="reference internal" href="#c.PyLong_GetNativeLayout" title="PyLong_GetNativeLayout"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetNativeLayout()</span></code></a> to get the native layout of Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> objects, used internally for integers with “big enough” absolute value.</p> <p>See also <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.int_info" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.int_info</span></code></a> which exposes similar information to Python.</p> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongLayout.bits_per_digit"> <span class="n"><span class="pre">uint8_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">bits_per_digit</span></span></span><br /></dt> <dd>Bits per digit. For example, a 15 bit digit means that bits 0-14 contain meaningful information.</dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongLayout.digit_size"> <span class="n"><span class="pre">uint8_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">digit_size</span></span></span><br /></dt> <dd>Digit size in bytes. For example, a 15 bit digit will require at least 2 bytes.</dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongLayout.digits_order"> <span class="n"><span class="pre">int8_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">digits_order</span></span></span><br /></dt> <dd>Digits order:<ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">1</span></code> for most significant digit first</li> <li><code class="docutils literal notranslate"><span class="pre">-1</span></code> for least significant digit first</li> </ul> </dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongLayout.digit_endianness"> <span class="n"><span class="pre">int8_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">digit_endianness</span></span></span><br /></dt> <dd>Digit endianness:<ul class="simple"> <li><code class="docutils literal notranslate"><span class="pre">1</span></code> for most significant byte first (big endian)</li> <li><code class="docutils literal notranslate"><span class="pre">-1</span></code> for least significant byte first (little endian)</li> </ul> </dd></dl> </dd></dl> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLong_GetNativeLayout"> <span class="k"><span class="pre">const</span></span><span class="w"> </span><a class="reference internal" href="#c.PyLongLayout" title="PyLongLayout"><span class="n"><span class="pre">PyLongLayout</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="sig-name descname"><span class="n"><span class="pre">PyLong_GetNativeLayout</span></span></span><span class="sig-paren">(</span><span class="kt"><span class="pre">void</span></span><span class="sig-paren">)</span><br /></dt> <dd>Get the native layout of Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> objects.<p>See the <a class="reference internal" href="#c.PyLongLayout" title="PyLongLayout"><code class="xref c c-struct docutils literal notranslate"><span class="pre">PyLongLayout</span></code></a> structure.</p> <p>The function must not be called before Python initialization nor after Python finalization. The returned layout is valid until Python is finalized. The layout is the same for all Python sub-interpreters and so it can be cached.</p> </dd></dl> </section> <section id="id1"> <h3><a class="toc-backref" href="#id1" role="doc-backlink">Export API</a></h3> <dl class="c struct"> <dt class="sig sig-object c" id="c.PyLongExport"> <span class="k"><span class="pre">struct</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLongExport</span></span></span><br /></dt> <dd>Export of a Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object.<p>There are two cases:</p> <ul class="simple"> <li>If <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, only use the <a class="reference internal" href="#c.PyLongExport.value" title="value"><code class="xref c c-member docutils literal notranslate"><span class="pre">value</span></code></a> member.</li> <li>If <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, use <a class="reference internal" href="#c.PyLongExport.negative" title="negative"><code class="xref c c-member docutils literal notranslate"><span class="pre">negative</span></code></a>, <a class="reference internal" href="#c.PyLongExport.ndigits" title="ndigits"><code class="xref c c-member docutils literal notranslate"><span class="pre">ndigits</span></code></a> and <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> members.</li> </ul> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongExport.value"> <span class="n"><span class="pre">int64_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">value</span></span></span><br /></dt> <dd>The native integer value of the exported <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object. Only valid if <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongExport.negative"> <span class="n"><span class="pre">uint8_t</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">negative</span></span></span><br /></dt> <dd>1 if the number is negative, 0 otherwise. Only valid if <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongExport.ndigits"> <a class="reference external" href="https://docs.python.org/3/c-api/intro.html#c.Py_ssize_t" title="(in Python v3.13)"><span class="n"><span class="pre">Py_ssize_t</span></span></a><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">ndigits</span></span></span><br /></dt> <dd>Number of digits in <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> array. Only valid if <a class="reference internal" href="#c.PyLongExport.digits" title="digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">digits</span></code></a> is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</dd></dl> <dl class="c member"> <dt class="sig sig-object c" id="c.PyLongExport.digits"> <span class="k"><span class="pre">const</span></span><span class="w"> </span><span class="kt"><span class="pre">void</span></span><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="sig-name descname"><span class="n"><span class="pre">digits</span></span></span><br /></dt> <dd>Read-only array of unsigned digits. Can be <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</dd></dl> </dd></dl> <p>If <a class="reference internal" href="#c.PyLongExport.digits" title="PyLongExport.digits"><code class="xref c c-member docutils literal notranslate"><span class="pre">PyLongExport.digits</span></code></a> is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, a private field of the <a class="reference internal" href="#c.PyLongExport" title="PyLongExport"><code class="xref c c-struct docutils literal notranslate"><span class="pre">PyLongExport</span></code></a> structure stores a strong reference to the Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object to make sure that that structure remains valid until <a class="reference internal" href="#c.PyLong_FreeExport" title="PyLong_FreeExport"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FreeExport()</span></code></a> is called.</p> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLong_Export"> <span class="kt"><span class="pre">int</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLong_Export</span></span></span><span class="sig-paren">(</span><a class="reference external" href="https://docs.python.org/3/c-api/structures.html#c.PyObject" title="(in Python v3.13)"><span class="n"><span class="pre">PyObject</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">obj</span></span>, <a class="reference internal" href="#c.PyLongExport" title="PyLongExport"><span class="n"><span class="pre">PyLongExport</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">export_long</span></span><span class="sig-paren">)</span><br /></dt> <dd>Export a Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object.<p><em>export_long</em> must point to a <a class="reference internal" href="#c.PyLongExport" title="PyLongExport"><code class="xref c c-struct docutils literal notranslate"><span class="pre">PyLongExport</span></code></a> structure allocated by the caller. It must not be <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p> <p>On success, fill in <em>*export_long</em> and return 0. On error, set an exception and return -1.</p> <p><a class="reference internal" href="#c.PyLong_FreeExport" title="PyLong_FreeExport"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FreeExport()</span></code></a> must be called when the export is no longer needed.</p> <p><strong>CPython implementation detail</strong>: This function always succeeds if <em>obj</em> is a Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object or a subclass.</p> </dd></dl> <p>On CPython 3.14, no memory copy is needed in <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a>, it’s just a thin wrapper to expose Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> internal digits array.</p> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLong_FreeExport"> <span class="kt"><span class="pre">void</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLong_FreeExport</span></span></span><span class="sig-paren">(</span><a class="reference internal" href="#c.PyLongExport" title="PyLongExport"><span class="n"><span class="pre">PyLongExport</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">export_long</span></span><span class="sig-paren">)</span><br /></dt> <dd>Release the export <em>export_long</em> created by <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a>.<p><strong>CPython implementation detail</strong>: Calling <a class="reference internal" href="#c.PyLong_FreeExport" title="PyLong_FreeExport"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FreeExport()</span></code></a> is optional if <em>export_long-&gt;digits</em> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p> </dd></dl> </section> <section id="import-api"> <h3><a class="toc-backref" href="#import-api" role="doc-backlink">Import API</a></h3> <p>The <a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongWriter</span></code></a> API can be used to import an integer.</p> <dl class="c struct"> <dt class="sig sig-object c" id="c.PyLongWriter"> <span class="k"><span class="pre">struct</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLongWriter</span></span></span><br /></dt> <dd>A Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> writer instance.<p>The instance must be destroyed by <a class="reference internal" href="#c.PyLongWriter_Finish" title="PyLongWriter_Finish"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Finish()</span></code></a> or <a class="reference internal" href="#c.PyLongWriter_Discard" title="PyLongWriter_Discard"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Discard()</span></code></a>.</p> </dd></dl> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLongWriter_Create"> <a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><span class="n"><span class="pre">PyLongWriter</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="sig-name descname"><span class="n"><span class="pre">PyLongWriter_Create</span></span></span><span class="sig-paren">(</span><span class="kt"><span class="pre">int</span></span><span class="w"> </span><span class="n"><span class="pre">negative</span></span>, <a class="reference external" href="https://docs.python.org/3/c-api/intro.html#c.Py_ssize_t" title="(in Python v3.13)"><span class="n"><span class="pre">Py_ssize_t</span></span></a><span class="w"> </span><span class="n"><span class="pre">ndigits</span></span>, <span class="kt"><span class="pre">void</span></span><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">digits</span></span><span class="sig-paren">)</span><br /></dt> <dd>Create a <a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongWriter</span></code></a>.<p>On success, allocate <em>*digits</em> and return a writer. On error, set an exception and return <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p> <p><em>negative</em> is <code class="docutils literal notranslate"><span class="pre">1</span></code> if the number is negative, or <code class="docutils literal notranslate"><span class="pre">0</span></code> otherwise.</p> <p><em>ndigits</em> is the number of digits in the <em>digits</em> array. It must be greater than 0.</p> <p><em>digits</em> must not be NULL.</p> <p>After a successful call to this function, the caller should fill in the array of digits <em>digits</em> and then call <a class="reference internal" href="#c.PyLongWriter_Finish" title="PyLongWriter_Finish"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Finish()</span></code></a> to get a Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a>. The layout of <em>digits</em> is described by <a class="reference internal" href="#c.PyLong_GetNativeLayout" title="PyLong_GetNativeLayout"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetNativeLayout()</span></code></a>.</p> <p>Digits must be in the range [<code class="docutils literal notranslate"><span class="pre">0</span></code>; <code class="docutils literal notranslate"><span class="pre">(1</span> <span class="pre">&lt;&lt;</span> <span class="pre">bits_per_digit)</span> <span class="pre">-</span> <span class="pre">1</span></code>] (where the <a class="reference internal" href="#c.PyLongLayout.bits_per_digit" title="PyLongLayout.bits_per_digit"><code class="xref c c-struct docutils literal notranslate"><span class="pre">bits_per_digit</span></code></a> is the number of bits per digit). Any unused most significant digits must be set to <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p> <p>Alternately, call <a class="reference internal" href="#c.PyLongWriter_Discard" title="PyLongWriter_Discard"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Discard()</span></code></a> to destroy the writer instance without creating an <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object.</p> </dd></dl> <p>On CPython 3.14, the <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a> implementation is a thin wrapper to the private <code class="xref c c-func docutils literal notranslate"><span class="pre">_PyLong_New()</span></code> function.</p> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLongWriter_Finish"> <a class="reference external" href="https://docs.python.org/3/c-api/structures.html#c.PyObject" title="(in Python v3.13)"><span class="n"><span class="pre">PyObject</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="sig-name descname"><span class="n"><span class="pre">PyLongWriter_Finish</span></span></span><span class="sig-paren">(</span><a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><span class="n"><span class="pre">PyLongWriter</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">writer</span></span><span class="sig-paren">)</span><br /></dt> <dd>Finish a <a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongWriter</span></code></a> created by <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a>.<p>On success, return a Python <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> object. On error, set an exception and return <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p> <p>The function takes care of normalizing the digits and converts the object to a compact integer if needed.</p> <p>The writer instance and the <em>digits</em> array are invalid after the call.</p> </dd></dl> <dl class="c function"> <dt class="sig sig-object c" id="c.PyLongWriter_Discard"> <span class="kt"><span class="pre">void</span></span><span class="w"> </span><span class="sig-name descname"><span class="n"><span class="pre">PyLongWriter_Discard</span></span></span><span class="sig-paren">(</span><a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><span class="n"><span class="pre">PyLongWriter</span></span></a><span class="w"> </span><span class="p"><span class="pre">*</span></span><span class="n"><span class="pre">writer</span></span><span class="sig-paren">)</span><br /></dt> <dd>Discard a <a class="reference internal" href="#c.PyLongWriter" title="PyLongWriter"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongWriter</span></code></a> created by <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a>.<p><em>writer</em> must not be <code class="docutils literal notranslate"><span class="pre">NULL</span></code>.</p> <p>The writer instance and the <em>digits</em> array are invalid after the call.</p> </dd></dl> </section> </section> <section id="optimize-import-for-small-integers"> <h2><a class="toc-backref" href="#optimize-import-for-small-integers" role="doc-backlink">Optimize import for small integers</a></h2> <p>Proposed import API is efficient for large integers. Compared to accessing directly Python internals, the proposed import API can have a significant performance overhead on small integers.</p> <p>For small integers of a few digits (for example, 1 or 2 digits), existing APIs can be used:</p> <ul class="simple"> <li><a class="reference external" href="https://docs.python.org/3.14/c-api/long.html#c.PyLong_FromUInt64" title="(in Python v3.14)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FromUInt64()</span></code></a>;</li> <li><a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromLong" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FromLong()</span></code></a>;</li> <li><a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromNativeBytes" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FromNativeBytes()</span></code></a>.</li> </ul> </section> <section id="implementation"> <h2><a class="toc-backref" href="#implementation" role="doc-backlink">Implementation</a></h2> <ul class="simple"> <li>CPython:<ul> <li><a class="reference external" href="https://github.com/python/cpython/pull/121339">https://github.com/python/cpython/pull/121339</a></li> <li><a class="reference external" href="https://github.com/vstinner/cpython/pull/5">https://github.com/vstinner/cpython/pull/5</a></li> </ul> </li> <li>gmpy:<ul> <li><a class="reference external" href="https://github.com/aleaxit/gmpy/pull/495">https://github.com/aleaxit/gmpy/pull/495</a></li> </ul> </li> </ul> </section> <section id="benchmarks"> <h2><a class="toc-backref" href="#benchmarks" role="doc-backlink">Benchmarks</a></h2> <p>Code:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* Query parameters of Python’s internal representation of integers. */</span> <span class="k">const</span><span class="w"> </span><span class="n">PyLongLayout</span><span class="w"> </span><span class="o">*</span><span class="n">layout</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_GetNativeLayout</span><span class="p">();</span> <span class="kt">size_t</span><span class="w"> </span><span class="n">int_digit_size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">layout</span><span class="o">-&gt;</span><span class="n">digit_size</span><span class="p">;</span> <span class="kt">int</span><span class="w"> </span><span class="n">int_digits_order</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">layout</span><span class="o">-&gt;</span><span class="n">digits_order</span><span class="p">;</span> <span class="kt">size_t</span><span class="w"> </span><span class="n">int_bits_per_digit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">layout</span><span class="o">-&gt;</span><span class="n">bits_per_digit</span><span class="p">;</span> <span class="kt">size_t</span><span class="w"> </span><span class="n">int_nails</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">int_digit_size</span><span class="o">*</span><span class="mi">8</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">int_bits_per_digit</span><span class="p">;</span> <span class="kt">int</span><span class="w"> </span><span class="n">int_endianness</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">layout</span><span class="o">-&gt;</span><span class="n">digit_endianness</span><span class="p">;</span> </pre></div> </div> <section id="export-pylong-export-with-gmpy2"> <h3><a class="toc-backref" href="#export-pylong-export-with-gmpy2" role="doc-backlink">Export: <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a> with gmpy2</a></h3> <p>Code:</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="nf">mpz_set_PyLong</span><span class="p">(</span><span class="n">mpz_t</span><span class="w"> </span><span class="n">z</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">obj</span><span class="p">)</span> <span class="p">{</span> <span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="n">PyLongExport</span><span class="w"> </span><span class="n">long_export</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">PyLong_Export</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">long_export</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</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">-1</span><span class="p">;</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">long_export</span><span class="p">.</span><span class="n">digits</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_import</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">long_export</span><span class="p">.</span><span class="n">ndigits</span><span class="p">,</span><span class="w"> </span><span class="n">int_digits_order</span><span class="p">,</span><span class="w"> </span><span class="n">int_digit_size</span><span class="p">,</span> <span class="w"> </span><span class="n">int_endianness</span><span class="p">,</span><span class="w"> </span><span class="n">int_nails</span><span class="p">,</span><span class="w"> </span><span class="n">long_export</span><span class="p">.</span><span class="n">digits</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">long_export</span><span class="p">.</span><span class="n">negative</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_neg</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">);</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="n">PyLong_FreeExport</span><span class="p">(</span><span class="o">&amp;</span><span class="n">long_export</span><span class="p">);</span> <span class="w"> </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">const</span><span class="w"> </span><span class="kt">int64_t</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">long_export</span><span class="p">.</span><span class="n">value</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">LONG_MIN</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">LONG_MAX</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_set_si</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span> <span class="w"> </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">mpz_import</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">-1</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">int64_t</span><span class="p">),</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">value</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">value</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_t</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span> <span class="w"> </span><span class="n">mpz_init</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_ui_pow_ui</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">64</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_sub</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">tmp</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_clear</span><span class="p">(</span><span class="n">tmp</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="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>Reference code: <a class="reference external" href="https://github.com/aleaxit/gmpy/blob/9177648c23f5c507e46b81c1eb7d527c79c96f00/src/gmpy2_convert_gmp.c#L42-L69">mpz_set_PyLong() in the gmpy2 master for commit 9177648</a>.</p> <p>Benchmark:</p> <div class="highlight-py notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">pyperf</span> <span class="kn">from</span><span class="w"> </span><span class="nn">gmpy2</span><span class="w"> </span><span class="kn">import</span> <span class="n">mpz</span> <span class="n">runner</span> <span class="o">=</span> <span class="n">pyperf</span><span class="o">.</span><span class="n">Runner</span><span class="p">()</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;7&#39;</span><span class="p">,</span> <span class="n">mpz</span><span class="p">,</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">7</span><span class="p">)</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;38&#39;</span><span class="p">,</span> <span class="n">mpz</span><span class="p">,</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">38</span><span class="p">)</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;300&#39;</span><span class="p">,</span> <span class="n">mpz</span><span class="p">,</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">300</span><span class="p">)</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;3000&#39;</span><span class="p">,</span> <span class="n">mpz</span><span class="p">,</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">3000</span><span class="p">)</span> </pre></div> </div> <p>Results on Linux Fedora 40 with CPU isolation, Python built in release mode:</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Benchmark</th> <th class="head">ref</th> <th class="head">pep757</th> </tr> </thead> <tbody> <tr class="row-even"><td>1&lt;&lt;7</td> <td>91.3 ns</td> <td>89.9 ns: 1.02x faster</td> </tr> <tr class="row-odd"><td>1&lt;&lt;38</td> <td>120 ns</td> <td>94.9 ns: 1.27x faster</td> </tr> <tr class="row-even"><td>1&lt;&lt;300</td> <td>196 ns</td> <td>203 ns: 1.04x slower</td> </tr> <tr class="row-odd"><td>1&lt;&lt;3000</td> <td>939 ns</td> <td>945 ns: 1.01x slower</td> </tr> <tr class="row-even"><td>Geometric mean</td> <td>(ref)</td> <td>1.05x faster</td> </tr> </tbody> </table> </section> <section id="import-pylongwriter-create-with-gmpy2"> <h3><a class="toc-backref" href="#import-pylongwriter-create-with-gmpy2" role="doc-backlink">Import: <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a> with gmpy2</a></h3> <p>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">GMPy_PyLong_From_MPZ</span><span class="p">(</span><span class="n">MPZ_Object</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="n">CTXT_Object</span><span class="w"> </span><span class="o">*</span><span class="n">context</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">mpz_fits_slong_p</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">z</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="n">PyLong_FromLong</span><span class="p">(</span><span class="n">mpz_get_si</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">z</span><span class="p">));</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="kt">size_t</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">mpz_sizeinbase</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="n">int_bits_per_digit</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="o">/</span><span class="w"> </span><span class="n">int_bits_per_digit</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">digits</span><span class="p">;</span> <span class="w"> </span><span class="n">PyLongWriter</span><span class="w"> </span><span class="o">*</span><span class="n">writer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLongWriter_Create</span><span class="p">(</span><span class="n">mpz_sgn</span><span class="p">(</span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">z</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="p">,</span> <span class="w"> </span><span class="o">&amp;</span><span class="n">digits</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">writer</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="n">mpz_export</span><span class="p">(</span><span class="n">digits</span><span class="p">,</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">int_digits_order</span><span class="p">,</span><span class="w"> </span><span class="n">int_digit_size</span><span class="p">,</span> <span class="w"> </span><span class="n">int_endianness</span><span class="p">,</span><span class="w"> </span><span class="n">int_nails</span><span class="p">,</span><span class="w"> </span><span class="n">obj</span><span class="o">-&gt;</span><span class="n">z</span><span class="p">);</span> <span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">PyLongWriter_Finish</span><span class="p">(</span><span class="n">writer</span><span class="p">);</span> <span class="p">}</span> </pre></div> </div> <p>Reference code: <a class="reference external" href="https://github.com/aleaxit/gmpy/blob/9177648c23f5c507e46b81c1eb7d527c79c96f00/src/gmpy2_convert_gmp.c#L128-L156">GMPy_PyLong_From_MPZ() in the gmpy2 master for commit 9177648</a>.</p> <p>Benchmark:</p> <div class="highlight-py notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">pyperf</span> <span class="kn">from</span><span class="w"> </span><span class="nn">gmpy2</span><span class="w"> </span><span class="kn">import</span> <span class="n">mpz</span> <span class="n">runner</span> <span class="o">=</span> <span class="n">pyperf</span><span class="o">.</span><span class="n">Runner</span><span class="p">()</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;7&#39;</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">7</span><span class="p">))</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;38&#39;</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">38</span><span class="p">))</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;300&#39;</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">300</span><span class="p">))</span> <span class="n">runner</span><span class="o">.</span><span class="n">bench_func</span><span class="p">(</span><span class="s1">&#39;1&lt;&lt;3000&#39;</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="n">mpz</span><span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">3000</span><span class="p">))</span> </pre></div> </div> <p>Results on Linux Fedora 40 with CPU isolation, Python built in release mode:</p> <table class="docutils align-default"> <thead> <tr class="row-odd"><th class="head">Benchmark</th> <th class="head">ref</th> <th class="head">pep757</th> </tr> </thead> <tbody> <tr class="row-even"><td>1&lt;&lt;7</td> <td>56.7 ns</td> <td>56.2 ns: 1.01x faster</td> </tr> <tr class="row-odd"><td>1&lt;&lt;300</td> <td>191 ns</td> <td>213 ns: 1.12x slower</td> </tr> <tr class="row-even"><td>Geometric mean</td> <td>(ref)</td> <td>1.03x slower</td> </tr> </tbody> </table> <p>Benchmark hidden because not significant (2): 1&lt;&lt;38, 1&lt;&lt;3000.</p> </section> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>There is no impact on the backward compatibility, only new APIs are added.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> <section id="support-arbitrary-layout"> <h3><a class="toc-backref" href="#support-arbitrary-layout" role="doc-backlink">Support arbitrary layout</a></h3> <p>It would be convenient to support arbitrary layout to import-export Python integers.</p> <p>For example, it was proposed to add a <em>layout</em> parameter to <a class="reference internal" href="#c.PyLongWriter_Create" title="PyLongWriter_Create"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code></a> and a <em>layout</em> member to the <a class="reference internal" href="#c.PyLongExport" title="PyLongExport"><code class="xref c c-struct docutils literal notranslate"><span class="pre">PyLongExport</span></code></a> structure.</p> <p>The problem is that it’s more complex to implement and not really needed. What’s strictly needed is only an API to import-export using the Python “native” layout.</p> <p>If later there are use cases for arbitrary layouts, new APIs can be added.</p> </section> <section id="don-t-add-pylong-getnativelayout-function"> <h3><a class="toc-backref" href="#don-t-add-pylong-getnativelayout-function" role="doc-backlink">Don’t add <a class="reference internal" href="#c.PyLong_GetNativeLayout" title="PyLong_GetNativeLayout"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetNativeLayout()</span></code></a> function</a></h3> <p>Currently, most required information for <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> import/export is already available via <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_GetInfo" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetInfo()</span></code></a> (and <a class="reference external" href="https://docs.python.org/3/library/sys.html#sys.int_info" title="(in Python v3.13)"><code class="xref py py-data docutils literal notranslate"><span class="pre">sys.int_info</span></code></a>). We also can add more (like order of digits), this interface doesn’t poses any constraints on future evolution of the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLongObject" title="(in Python v3.13)"><code class="xref c c-type docutils literal notranslate"><span class="pre">PyLongObject</span></code></a>.</p> <p>The problem is that the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_GetInfo" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetInfo()</span></code></a> returns a Python object, <a class="reference external" href="https://docs.python.org/3/glossary.html#term-named-tuple" title="(in Python v3.13)"><span class="xref std std-term">named tuple</span></a>, not a convenient C structure and that might distract people from using it in favor e.g. of current semi-private macros like <code class="xref c c-macro docutils literal notranslate"><span class="pre">PyLong_SHIFT</span></code> and <code class="xref c c-macro docutils literal notranslate"><span class="pre">PyLong_BASE</span></code>.</p> </section> <section id="provide-mpz-import-export-like-api-instead"> <h3><a class="toc-backref" href="#provide-mpz-import-export-like-api-instead" role="doc-backlink">Provide mpz_import/export-like API instead</a></h3> <p>The other approach to import/export data from <a class="reference external" href="https://docs.python.org/3/library/functions.html#int" title="(in Python v3.13)"><code class="xref py py-class docutils literal notranslate"><span class="pre">int</span></code></a> objects might be following: expect, that C extensions provide contiguous buffers that CPython then exports (or imports) the <em>absolute</em> value of an integer.</p> <p>API example:</p> <div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">struct</span><span class="w"> </span><span class="nc">PyLongLayout</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">bits_per_digit</span><span class="p">;</span> <span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">digit_size</span><span class="p">;</span> <span class="w"> </span><span class="kt">int8_t</span><span class="w"> </span><span class="n">digits_order</span><span class="p">;</span> <span class="p">};</span> <span class="kt">size_t</span><span class="w"> </span><span class="nf">PyLong_GetDigitsNeeded</span><span class="p">(</span><span class="n">PyLongObject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="n">PyLongLayout</span><span class="w"> </span><span class="n">layout</span><span class="p">);</span> <span class="kt">int</span><span class="w"> </span><span class="nf">PyLong_Export</span><span class="p">(</span><span class="n">PyLongObject</span><span class="w"> </span><span class="o">*</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="n">PyLongLayout</span><span class="w"> </span><span class="n">layout</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">buffer</span><span class="p">);</span> <span class="n">PyLongObject</span><span class="w"> </span><span class="o">*</span><span class="nf">PyLong_Import</span><span class="p">(</span><span class="n">PyLongLayout</span><span class="w"> </span><span class="n">layout</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">buffer</span><span class="p">);</span> </pre></div> </div> <p>This might work for the GMP, as it has <code class="xref c c-func docutils literal notranslate"><span class="pre">mpz_limbs_read()</span></code> and <code class="xref c c-func docutils literal notranslate"><span class="pre">mpz_limbs_write()</span></code> functions, that can provide required access to internals of <code class="xref c c-struct docutils literal notranslate"><span class="pre">mpz_t</span></code>. Other libraries may require using temporary buffers and then mpz_import/export-like functions on their side.</p> <p>The major drawback of this approach is that it’s much more complex on the CPython side (i.e. actual conversion between different layouts). For example, implementation of the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_FromNativeBytes" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_FromNativeBytes()</span></code></a> and the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_AsNativeBytes" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_AsNativeBytes()</span></code></a> (together provided restricted version of the required API) in the CPython took ~500 LOC (c.f. ~100 LOC in the current implementation).</p> </section> <section id="drop-value-field-from-the-export-api"> <h3><a class="toc-backref" href="#drop-value-field-from-the-export-api" role="doc-backlink">Drop <a class="reference internal" href="#c.PyLongExport.value" title="PyLongExport.value"><code class="xref c c-member docutils literal notranslate"><span class="pre">value</span></code></a> field from the export API</a></h3> <p>With this suggestion, only one export type will exist (array of “digits”). If such view is not available for a given integer, it will be either emulated by export functions or the <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a> will return an error. In both cases, it’s assumed that users will use other C-API functions to get “small enough” integers (i.e., that fits to some machine integer types), like the <a class="reference external" href="https://docs.python.org/3/c-api/long.html#c.PyLong_AsLongAndOverflow" title="(in Python v3.13)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_AsLongAndOverflow()</span></code></a>. The <a class="reference internal" href="#c.PyLong_Export" title="PyLong_Export"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code></a> will be inefficient (or just fail) in this case.</p> <p>An 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="nf">mpz_set_PyLong</span><span class="p">(</span><span class="n">mpz_t</span><span class="w"> </span><span class="n">z</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">obj</span><span class="p">)</span> <span class="p">{</span> <span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">overflow</span><span class="p">;</span> <span class="cp">#if SIZEOF_LONG == 8</span> <span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_AsLongAndOverflow</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">overflow</span><span class="p">);</span> <span class="cp">#else</span> <span class="w"> </span><span class="cm">/* Windows has 32-bit long, so use 64-bit long long instead */</span> <span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="kt">long</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PyLong_AsLongLongAndOverflow</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">overflow</span><span class="p">);</span> <span class="cp">#endif</span> <span class="w"> </span><span class="n">Py_BUILD_ASSERT</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">value</span><span class="p">)</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">int64_t</span><span class="p">));</span> <span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="o">!</span><span class="n">overflow</span><span class="p">)</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">LONG_MIN</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">&lt;=</span><span class="w"> </span><span class="n">LONG_MAX</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_set_si</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">long</span><span class="p">)</span><span class="n">value</span><span class="p">);</span> <span class="w"> </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">mpz_import</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">-1</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="p">(</span><span class="kt">int64_t</span><span class="p">),</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">value</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">value</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_t</span><span class="w"> </span><span class="n">tmp</span><span class="p">;</span> <span class="w"> </span><span class="n">mpz_init</span><span class="p">(</span><span class="n">tmp</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_ui_pow_ui</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">64</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_sub</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">tmp</span><span class="p">);</span> <span class="w"> </span><span class="n">mpz_clear</span><span class="p">(</span><span class="n">tmp</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="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">static</span><span class="w"> </span><span class="n">PyLongExport</span><span class="w"> </span><span class="n">long_export</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">PyLong_Export</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">long_export</span><span class="p">)</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="mi">0</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">-1</span><span class="p">;</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="n">mpz_import</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">long_export</span><span class="p">.</span><span class="n">ndigits</span><span class="p">,</span><span class="w"> </span><span class="n">int_digits_order</span><span class="p">,</span><span class="w"> </span><span class="n">int_digit_size</span><span class="p">,</span> <span class="w"> </span><span class="n">int_endianness</span><span class="p">,</span><span class="w"> </span><span class="n">int_nails</span><span class="p">,</span><span class="w"> </span><span class="n">long_export</span><span class="p">.</span><span class="n">digits</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">long_export</span><span class="p">.</span><span class="n">negative</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">mpz_neg</span><span class="p">(</span><span class="n">z</span><span class="p">,</span><span class="w"> </span><span class="n">z</span><span class="p">);</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="n">PyLong_FreeExport</span><span class="p">(</span><span class="o">&amp;</span><span class="n">long_export</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>This might look as a simplification from the API designer point of view, but will be less convenient for end users. They will have to follow Python development, benchmark different variants for exporting small integers (is that obvious why above case was chosen instead of <a class="reference external" href="https://docs.python.org/3.14/c-api/long.html#c.PyLong_AsInt64" title="(in Python v3.14)"><code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_AsInt64()</span></code></a>?), maybe support different code paths for various CPython versions or across different Python implementations.</p> </section> </section> <section id="discussions"> <h2><a class="toc-backref" href="#discussions" role="doc-backlink">Discussions</a></h2> <ul class="simple"> <li>Discourse: <a class="reference external" href="https://discuss.python.org/t/63895">PEP 757 – C API to import-export Python integers</a></li> <li><a class="reference external" href="https://github.com/capi-workgroup/decisions/issues/35">C API Working Group decision issue #35</a></li> <li><a class="reference external" href="https://github.com/python/cpython/pull/121339">Pull request #121339</a></li> <li><a class="reference external" href="https://github.com/python/cpython/issues/102471">Issue #102471</a>: The C-API for Python to C integer conversion is, to be frank, a mess.</li> <li><a class="reference external" href="https://github.com/capi-workgroup/decisions/issues/31">Add public function PyLong_GetDigits()</a></li> <li><a class="reference external" href="https://github.com/python/cpython/issues/111415">Consider restoring _PyLong_New() function as public</a></li> <li><a class="reference external" href="https://github.com/python/cpython/pull/108604">Pull request gh-106320</a>: Remove private _PyLong_New() function.</li> </ul> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0757.rst">https://github.com/python/peps/blob/main/peps/pep-0757.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0757.rst">2024-12-16 07:23:59 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a><ul> <li><a class="reference internal" href="#layout-api">Layout API</a></li> <li><a class="reference internal" href="#id1">Export API</a></li> <li><a class="reference internal" href="#import-api">Import API</a></li> </ul> </li> <li><a class="reference internal" href="#optimize-import-for-small-integers">Optimize import for small integers</a></li> <li><a class="reference internal" href="#implementation">Implementation</a></li> <li><a class="reference internal" href="#benchmarks">Benchmarks</a><ul> <li><a class="reference internal" href="#export-pylong-export-with-gmpy2">Export: <code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_Export()</span></code> with gmpy2</a></li> <li><a class="reference internal" href="#import-pylongwriter-create-with-gmpy2">Import: <code class="xref c c-func docutils literal notranslate"><span class="pre">PyLongWriter_Create()</span></code> with gmpy2</a></li> </ul> </li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a><ul> <li><a class="reference internal" href="#support-arbitrary-layout">Support arbitrary layout</a></li> <li><a class="reference internal" href="#don-t-add-pylong-getnativelayout-function">Don’t add <code class="xref c c-func docutils literal notranslate"><span class="pre">PyLong_GetNativeLayout()</span></code> function</a></li> <li><a class="reference internal" href="#provide-mpz-import-export-like-api-instead">Provide mpz_import/export-like API instead</a></li> <li><a class="reference internal" href="#drop-value-field-from-the-export-api">Drop <code class="xref c c-member docutils literal notranslate"><span class="pre">value</span></code> field from the export API</a></li> </ul> </li> <li><a class="reference internal" href="#discussions">Discussions</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0757.rst">Page Source (GitHub)</a> </nav> </section> <script src="../_static/colour_scheme.js"></script> <script src="../_static/wrap_tables.js"></script> <script src="../_static/sticky_banner.js"></script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10