475 lines
30 KiB
HTML
475 lines
30 KiB
HTML
|
||
<!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 611 – The one million limit | peps.python.org</title>
|
||
<link rel="shortcut icon" href="../_static/py.png">
|
||
<link rel="canonical" href="https://peps.python.org/pep-0611/">
|
||
<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 611 – The one million limit | peps.python.org'>
|
||
<meta property="og:description" content="This PR proposes a soft limit of one million (1 000 000), and a larger hard limit for various aspects of Python code and its implementation.">
|
||
<meta property="og:type" content="website">
|
||
<meta property="og:url" content="https://peps.python.org/pep-0611/">
|
||
<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="This PR proposes a soft limit of one million (1 000 000), and a larger hard limit for various aspects of Python code and its implementation.">
|
||
<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> » </li>
|
||
<li><a href="../pep-0000/">PEP Index</a> » </li>
|
||
<li>PEP 611</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 611 – The one million limit</h1>
|
||
<dl class="rfc2822 field-list simple">
|
||
<dt class="field-odd">Author<span class="colon">:</span></dt>
|
||
<dd class="field-odd">Mark Shannon <mark at hotpy.org></dd>
|
||
<dt class="field-even">Status<span class="colon">:</span></dt>
|
||
<dd class="field-even"><abbr title="Removed from consideration by sponsor or authors">Withdrawn</abbr></dd>
|
||
<dt class="field-odd">Type<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><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-even">Created<span class="colon">:</span></dt>
|
||
<dd class="field-even">05-Dec-2019</dd>
|
||
<dt class="field-odd">Post-History<span class="colon">:</span></dt>
|
||
<dd class="field-odd"><p></p></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="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#is-this-a-worthwhile-trade-off">Is this a worthwhile trade off?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#one-million">One million</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#recursion-depth">Recursion depth</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#soft-and-hard-limits">Soft and hard limits</a><ul>
|
||
<li><a class="reference internal" href="#introspecting-and-modifying-the-limits">Introspecting and modifying the limits</a></li>
|
||
<li><a class="reference internal" href="#inferred-limits">Inferred limits</a></li>
|
||
<li><a class="reference internal" href="#the-advantages-for-cpython-of-imposing-these-limits">The advantages for CPython of imposing these limits:</a><ul>
|
||
<li><a class="reference internal" href="#line-of-code-in-a-module-and-code-object-restrictions">Line of code in a module and code object restrictions.</a></li>
|
||
<li><a class="reference internal" href="#total-number-of-classes-in-a-running-interpreter">Total number of classes in a running interpreter</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#enforcement">Enforcement</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#hard-limits-in-cpython">Hard limits in CPython</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
|
||
<li><a class="reference internal" href="#other-implementations">Other implementations</a><ul>
|
||
<li><a class="reference internal" href="#general-purpose-implementations">General purpose implementations</a></li>
|
||
<li><a class="reference internal" href="#special-purpose-implementations">Special purpose implementations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a></li>
|
||
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
|
||
<li><a class="reference internal" href="#references">References</a></li>
|
||
<li><a class="reference internal" href="#copyright">Copyright</a></li>
|
||
</ul>
|
||
</details></section>
|
||
<section id="abstract">
|
||
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
|
||
<p>This PR proposes a soft limit of one million (1 000 000), and a larger hard limit
|
||
for various aspects of Python code and its implementation.</p>
|
||
<p>The Python language does not specify limits for many of its features.
|
||
Not having any limit to these values seems to enhance programmer freedom,
|
||
at least superficially, but in practice the CPython VM and other Python virtual
|
||
machines have implicit limits or are forced to assume that the limits are
|
||
astronomical, which is expensive.</p>
|
||
<p>This PR lists a number of features which are to have a limit of one million.</p>
|
||
<p>For CPython the hard limit will be eight million (8 000 000).</p>
|
||
</section>
|
||
<section id="motivation">
|
||
<h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2>
|
||
<p>There are many values that need to be represented in a virtual machine.
|
||
If no limit is specified for these values,
|
||
then the representation must either be inefficient or vulnerable to overflow.
|
||
The CPython virtual machine represents values like line numbers,
|
||
stack offsets and instruction offsets by 32 bit values. This is inefficient, and potentially unsafe.</p>
|
||
<p>It is inefficient as actual values rarely need more than a dozen or so bits to represent them.</p>
|
||
<p>It is unsafe as malicious or poorly generated code could cause values to exceed 2<sup>32</sup>.</p>
|
||
<p>For example, line numbers are represented by 32 bit values internally.
|
||
This is inefficient, given that modules almost never exceed a few thousand lines.
|
||
Despite being inefficient, it is still vulnerable to overflow as
|
||
it is easy for an attacker to created a module with billions of newline characters.</p>
|
||
<p>Memory access is usually a limiting factor in the performance of modern CPUs.
|
||
Better packing of data structures enhances locality and reduces memory bandwidth,
|
||
at a modest increase in ALU usage (for shifting and masking).
|
||
Being able to safely store important values in 20 bits would allow memory savings
|
||
in several data structures including, but not limited to:</p>
|
||
<ul class="simple">
|
||
<li>Frame objects</li>
|
||
<li>Object headers</li>
|
||
<li>Code objects</li>
|
||
</ul>
|
||
<p>There is also the potential for a more efficient instruction format, speeding up interpreter dispatch.</p>
|
||
<section id="is-this-a-worthwhile-trade-off">
|
||
<h3><a class="toc-backref" href="#is-this-a-worthwhile-trade-off" role="doc-backlink">Is this a worthwhile trade off?</a></h3>
|
||
<p>The downside of any form of limit is that it might potentially make someone’s job harder,
|
||
for example, it may be harder to write a code generator that keeps the size of modules to one million lines.
|
||
However, it is the author’s opinion, having written many code generators,
|
||
that such a limit is extremely unlikely to be a problem in practice.</p>
|
||
<p>The upside of these limits is the freedom it grants implementers of runtimes, whether CPython,
|
||
PyPy, or any other implementation, to improve performance.
|
||
It is the author’s belief, that the potential value of even a 0.1% reduction in the cost
|
||
of running Python programs globally will hugely exceed the cost of modifying a handful of code generators.</p>
|
||
</section>
|
||
</section>
|
||
<section id="rationale">
|
||
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
|
||
<p>Imposing a limit on values such as lines of code in a module, and the number of local variables,
|
||
has significant advantages for ease of implementation and efficiency of virtual machines.
|
||
If the limit is sufficiently large, there is no adverse effect on users of the language.</p>
|
||
<p>By selecting a fixed but large limit for these values,
|
||
it is possible to have both safety and efficiency whilst causing no inconvenience to human programmers
|
||
and only very rare problems for code generators.</p>
|
||
<section id="one-million">
|
||
<h3><a class="toc-backref" href="#one-million" role="doc-backlink">One million</a></h3>
|
||
<p>The value “one million” is very easy to remember.</p>
|
||
<p>The one million limit is mostly a limit on human generated code, not runtime sizes.</p>
|
||
<p>One million lines in a single module is a ridiculous concentration of code;
|
||
the entire Python standard library is about 2/3rd of a million lines, spread over 1600 files.</p>
|
||
<p>The Java Virtual Machine (JVM) <a class="footnote-reference brackets" href="#id2" id="id1">[1]</a> specifies a limit of 2<sup>16</sup>-1 (65535) for many program
|
||
elements similar to those covered here.
|
||
This limit enables limited values to fit in 16 bits, which is a very efficient machine representation.
|
||
However, this limit is quite easily exceeded in practice by code generators and
|
||
the author is aware of existing Python code that already exceeds 2<sup>16</sup> lines of code.</p>
|
||
<p>The hard limit of eight million fits into 23 bits which, although not as convenient for machine representation,
|
||
is still reasonably compact.
|
||
A limit of eight million is small enough for efficiency advantages (only 23 bits),
|
||
but large enough not to impact users (no one has ever written a module that large).</p>
|
||
<p>While it is possible that generated code could exceed the limit,
|
||
it is easy for a code generator to modify its output to conform.
|
||
The author has hit the 64K limit in the JVM on at least two occasions when generating Java code.
|
||
The workarounds were relatively straightforward and wouldn’t
|
||
have been necessary with a limit of one million bytecodes or lines of code.</p>
|
||
<p>Where necessary, the soft limit can increased for those programs that exceed the one million limit.</p>
|
||
<p>Having a soft limit of one million provides a warning of problematic code, without causing an error and forcing an immediate fix.
|
||
It also allows dynamic optimizers to use more compact formats without inline checks.</p>
|
||
</section>
|
||
</section>
|
||
<section id="specification">
|
||
<h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2>
|
||
<p>This PR proposes that the following language features and runtime values have a soft limit of one million.</p>
|
||
<ul class="simple">
|
||
<li>The number of source code lines in a module</li>
|
||
<li>The number of bytecode instructions in a code object.</li>
|
||
<li>The sum of local variables and stack usage for a code object.</li>
|
||
<li>The number of classes in a running interpreter.</li>
|
||
<li>The recursion depth of Python code.</li>
|
||
</ul>
|
||
<p>It is likely that memory constraints would be a limiting factor before the number of classes reaches one million.</p>
|
||
<section id="recursion-depth">
|
||
<h3><a class="toc-backref" href="#recursion-depth" role="doc-backlink">Recursion depth</a></h3>
|
||
<p>The recursion depth limit only applies to pure Python code. Code written in a foreign language, such as C,
|
||
may consume hardware stack and thus be limited to a recursion depth of a few thousand.
|
||
It is expected that implementations will raise an exception should the hardware stack get close to its limit.
|
||
For code that mixes Python and C calls, it is most likely that the hardware limit will apply first.
|
||
The size of the hardware recursion may vary at runtime and will not be visible.</p>
|
||
</section>
|
||
</section>
|
||
<section id="soft-and-hard-limits">
|
||
<h2><a class="toc-backref" href="#soft-and-hard-limits" role="doc-backlink">Soft and hard limits</a></h2>
|
||
<p>Implementations should emit a warning whenever a soft limit is exceeded, unless the hard limit has the same value as the soft limit.
|
||
When a hard limit is exceeded, then an exception should be raised.</p>
|
||
<p>Depending on the implementation, different hard limits might apply. In some cases the hard limit might be below the soft limit.
|
||
For example, many micropython ports are unlikely to be able to support such large limits.</p>
|
||
<section id="introspecting-and-modifying-the-limits">
|
||
<h3><a class="toc-backref" href="#introspecting-and-modifying-the-limits" role="doc-backlink">Introspecting and modifying the limits</a></h3>
|
||
<p>One or more functions will be provided in the <code class="docutils literal notranslate"><span class="pre">sys</span></code> module to introspect or modify the soft limits at runtime,
|
||
but the limits may not be raised above the hard limit.</p>
|
||
</section>
|
||
<section id="inferred-limits">
|
||
<h3><a class="toc-backref" href="#inferred-limits" role="doc-backlink">Inferred limits</a></h3>
|
||
<p>These limits are not part of the specification, but a limit of less than one million
|
||
can be inferred from the limit on the number of bytecode instructions in a code object.
|
||
Because there would be insufficient instructions to load more than
|
||
one million constants or use more than one million names.</p>
|
||
<ul class="simple">
|
||
<li>The number of distinct names in a code object.</li>
|
||
<li>The number of constants in a code object.</li>
|
||
</ul>
|
||
</section>
|
||
<section id="the-advantages-for-cpython-of-imposing-these-limits">
|
||
<h3><a class="toc-backref" href="#the-advantages-for-cpython-of-imposing-these-limits" role="doc-backlink">The advantages for CPython of imposing these limits:</a></h3>
|
||
<section id="line-of-code-in-a-module-and-code-object-restrictions">
|
||
<h4><a class="toc-backref" href="#line-of-code-in-a-module-and-code-object-restrictions" role="doc-backlink">Line of code in a module and code object restrictions.</a></h4>
|
||
<p>When compiling source code to bytecode or modifying bytecode for profiling or debugging,
|
||
an intermediate form is required. By limiting operands to 23 bits,
|
||
instructions can be represented in a compact 64 bit form allowing
|
||
very fast passes over the instruction sequence.</p>
|
||
<p>Having 23 bit operands (24 bits for relative branches) allows instructions
|
||
to fit into 32 bits without needing additional <code class="docutils literal notranslate"><span class="pre">EXTENDED_ARG</span></code> instructions.
|
||
This improves dispatch, as the operand is strictly local to the instruction.
|
||
It is unclear whether this would help performance, it is merely an example of what is possible.</p>
|
||
<p>The benefit of restricting the number of lines in a module is primarily the implied limit on bytecodes.
|
||
It is more important for implementations that it is instructions per code object, not lines per module, that is limited to one million,
|
||
but it is much easier to explain a one million line limit. Having a consistent limit of one million is just easier to remember.
|
||
It is mostly likely, although not guaranteed, that the line limit will be hit first and thus provide a simpler to understand error message to the developer.</p>
|
||
</section>
|
||
<section id="total-number-of-classes-in-a-running-interpreter">
|
||
<h4><a class="toc-backref" href="#total-number-of-classes-in-a-running-interpreter" role="doc-backlink">Total number of classes in a running interpreter</a></h4>
|
||
<p>This limit has to the potential to reduce the size of object headers considerably.</p>
|
||
<p>Currently objects have a two word header, for objects without references
|
||
(int, float, str, etc.) or a four word header for objects with references.
|
||
By reducing the maximum number of classes, the space for the class reference
|
||
can be reduced from 64 bits to fewer than 32 bits allowing a much more compact header.</p>
|
||
<p>For example, a super-compact header format might look like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">struct</span> <span class="n">header</span> <span class="p">{</span>
|
||
<span class="n">uint32_t</span> <span class="n">gc_flags</span><span class="p">:</span><span class="mi">6</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Needs</span> <span class="n">finalisation</span><span class="p">,</span> <span class="n">might</span> <span class="n">be</span> <span class="n">part</span> <span class="n">of</span> <span class="n">a</span> <span class="n">cycle</span><span class="p">,</span> <span class="n">etc</span><span class="o">.</span> <span class="o">*/</span>
|
||
<span class="n">uint32_t</span> <span class="n">class_id</span><span class="p">:</span><span class="mi">26</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Can</span> <span class="n">be</span> <span class="n">efficiently</span> <span class="n">mapped</span> <span class="n">to</span> <span class="n">address</span> <span class="n">by</span> <span class="n">ensuring</span> <span class="n">suitable</span> <span class="n">alignment</span> <span class="n">of</span> <span class="n">classes</span> <span class="o">*/</span>
|
||
<span class="n">uint32_t</span> <span class="n">refcount</span><span class="p">;</span> <span class="o">/*</span> <span class="n">Limited</span> <span class="n">memory</span> <span class="ow">or</span> <span class="n">saturating</span> <span class="o">*/</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This format would reduce the size of a Python object without slots, on a 64 bit machine, from 40 to 16 bytes.</p>
|
||
<p>Note that there are two ways to use a 32 bit refcount on a 64 bit machine.
|
||
One is to limit each sub-interpreter to 32Gb of memory.
|
||
The other is to use a saturating reference count, which would be a little bit slower, but allow unlimited memory allocation.</p>
|
||
</section>
|
||
</section>
|
||
<section id="enforcement">
|
||
<h3><a class="toc-backref" href="#enforcement" role="doc-backlink">Enforcement</a></h3>
|
||
<p>Python implementations are not obliged to enforce the limits.
|
||
However, if a limit can be enforced without hurting performance, then it should be.</p>
|
||
<p>It is anticipated that CPython will enforce the limits as follows:</p>
|
||
<ul class="simple">
|
||
<li>The number of source code lines in a module: version 3.9 onward.</li>
|
||
<li>The number of bytecode instructions in a code object: 3.9 onward.</li>
|
||
<li>The sum of local variables and stack usage for a code object: 3.9 onward.</li>
|
||
<li>The number of classes in a running interpreter: probably 3.10 onward, maybe warning in 3.9.</li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
<section id="hard-limits-in-cpython">
|
||
<h2><a class="toc-backref" href="#hard-limits-in-cpython" role="doc-backlink">Hard limits in CPython</a></h2>
|
||
<p>CPython will enforce a hard limit on all the above values. The value of the hard limit will be 8 million.</p>
|
||
<p>It is hypothetically possible that some machine generated code exceeds one or more of the above limits.
|
||
The author believes that to be incredibly unlikely and easily fixed by modifying the output stage of the code generator.</p>
|
||
<p>We would like to gain the benefit from the above limits for performance as soon as possible.
|
||
To that end, CPython will start applying limits from version 3.9 onward.
|
||
To ease the transition and minimize breakage, the initial limits will be 16 million, reducing to 8 million in a later version.</p>
|
||
</section>
|
||
<section id="backwards-compatibility">
|
||
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
|
||
<p>The actual hard limits enforced by CPython will be:</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head">Version</th>
|
||
<th class="head">Hard limit</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td>3.9</td>
|
||
<td>16 million</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>3.10 onward</td>
|
||
<td>8 million</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Given the rarity of code generators that would exceed the one million limits,
|
||
and the environments in which they are typically used, it seems reasonable
|
||
to start issuing warnings in 3.9 if any limited quantity exceeds one million.</p>
|
||
<p>Historically the recursion limit has been set at 1000. To avoid breaking code that implicitly relies on the value being small,
|
||
the soft recursion limit will be increased gradually, as follows:</p>
|
||
<table class="docutils align-default">
|
||
<thead>
|
||
<tr class="row-odd"><th class="head">Version</th>
|
||
<th class="head">Soft limit</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="row-even"><td>3.9</td>
|
||
<td>4 000</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>3.10</td>
|
||
<td>16 000</td>
|
||
</tr>
|
||
<tr class="row-even"><td>3.11</td>
|
||
<td>64 000</td>
|
||
</tr>
|
||
<tr class="row-odd"><td>3.12</td>
|
||
<td>125 000</td>
|
||
</tr>
|
||
<tr class="row-even"><td>3.13</td>
|
||
<td>1 million</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>The hard limit will be set to 8 million immediately.</p>
|
||
</section>
|
||
<section id="other-implementations">
|
||
<h2><a class="toc-backref" href="#other-implementations" role="doc-backlink">Other implementations</a></h2>
|
||
<p>Implementations of Python other than CPython have different purposes, so different limits might be appropriate.
|
||
This is acceptable, provided the limits are clearly documented.</p>
|
||
<section id="general-purpose-implementations">
|
||
<h3><a class="toc-backref" href="#general-purpose-implementations" role="doc-backlink">General purpose implementations</a></h3>
|
||
<p>General purpose implementations, such as PyPy, should use the one million limit.
|
||
If maximum compatibility is a goal, then they should also follow CPython’s behaviour for 3.9 to 3.11.</p>
|
||
</section>
|
||
<section id="special-purpose-implementations">
|
||
<h3><a class="toc-backref" href="#special-purpose-implementations" role="doc-backlink">Special purpose implementations</a></h3>
|
||
<p>Special purpose implementations may use lower limits, as long as they are clearly documented.
|
||
An implementation designed for embedded systems, for example MicroPython, might impose limits as low as a few thousand.</p>
|
||
</section>
|
||
</section>
|
||
<section id="security-implications">
|
||
<h2><a class="toc-backref" href="#security-implications" role="doc-backlink">Security Implications</a></h2>
|
||
<p>Minimal. This reduces the attack surface of any Python virtual machine by a small amount.</p>
|
||
</section>
|
||
<section id="reference-implementation">
|
||
<h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2>
|
||
<p>None, as yet. This will be implemented in CPython, once the PEP has been accepted.</p>
|
||
</section>
|
||
<section id="rejected-ideas">
|
||
<h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2>
|
||
<p>Being able to modify the hard limits upwards at compile time was suggested by Tal Einat.
|
||
This is rejected as the current limits of 2<sup>32</sup> have not been an issue, and the practical
|
||
advantages of allowing limits between 2<sup>20</sup> and 2<sup>32</sup> seem slight compared to the additional
|
||
code complexity of supporting such a feature.</p>
|
||
</section>
|
||
<section id="open-issues">
|
||
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
|
||
<p>None, as yet.</p>
|
||
</section>
|
||
<section id="references">
|
||
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
|
||
<aside class="footnote-list brackets">
|
||
<aside class="footnote brackets" id="id2" role="doc-footnote">
|
||
<dt class="label" id="id2">[<a href="#id1">1</a>]</dt>
|
||
<dd>The Java Virtual Machine specification</aside>
|
||
</aside>
|
||
<p><a class="reference external" href="https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf">https://docs.oracle.com/javase/specs/jvms/se8/jvms8.pdf</a></p>
|
||
</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-0611.rst">https://github.com/python/peps/blob/main/peps/pep-0611.rst</a></p>
|
||
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0611.rst">2023-09-09 17:39:29 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="#motivation">Motivation</a><ul>
|
||
<li><a class="reference internal" href="#is-this-a-worthwhile-trade-off">Is this a worthwhile trade off?</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#rationale">Rationale</a><ul>
|
||
<li><a class="reference internal" href="#one-million">One million</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#specification">Specification</a><ul>
|
||
<li><a class="reference internal" href="#recursion-depth">Recursion depth</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#soft-and-hard-limits">Soft and hard limits</a><ul>
|
||
<li><a class="reference internal" href="#introspecting-and-modifying-the-limits">Introspecting and modifying the limits</a></li>
|
||
<li><a class="reference internal" href="#inferred-limits">Inferred limits</a></li>
|
||
<li><a class="reference internal" href="#the-advantages-for-cpython-of-imposing-these-limits">The advantages for CPython of imposing these limits:</a><ul>
|
||
<li><a class="reference internal" href="#line-of-code-in-a-module-and-code-object-restrictions">Line of code in a module and code object restrictions.</a></li>
|
||
<li><a class="reference internal" href="#total-number-of-classes-in-a-running-interpreter">Total number of classes in a running interpreter</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#enforcement">Enforcement</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#hard-limits-in-cpython">Hard limits in CPython</a></li>
|
||
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
|
||
<li><a class="reference internal" href="#other-implementations">Other implementations</a><ul>
|
||
<li><a class="reference internal" href="#general-purpose-implementations">General purpose implementations</a></li>
|
||
<li><a class="reference internal" href="#special-purpose-implementations">Special purpose implementations</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#security-implications">Security Implications</a></li>
|
||
<li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li>
|
||
<li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a></li>
|
||
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
|
||
<li><a class="reference internal" href="#references">References</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-0611.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> |