CINXE.COM
PEP 280 – Optimizing access to globals | 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 280 – Optimizing access to globals | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0280/"> <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 280 – Optimizing access to globals | peps.python.org'> <meta property="og:description" content="This PEP describes yet another approach to optimizing access to module globals, providing an alternative to PEP 266 (Optimizing Global Variable/Attribute Access by Skip Montanaro) and PEP 267 (Optimized Access to Module Namespaces by Jeremy Hylton)."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0280/"> <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 PEP describes yet another approach to optimizing access to module globals, providing an alternative to PEP 266 (Optimizing Global Variable/Attribute Access by Skip Montanaro) and PEP 267 (Optimized Access to Module Namespaces by Jeremy Hylton)."> <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 280</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 280 – Optimizing access to globals</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Guido van Rossum <guido at python.org></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Inactive draft that may be taken up again at a later time">Deferred</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">10-Feb-2002</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">2.3</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even"><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="#deferral">Deferral</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#description">Description</a></li> <li><a class="reference internal" href="#additional-ideas">Additional Ideas</a></li> <li><a class="reference internal" href="#faqs">FAQs</a></li> <li><a class="reference internal" href="#graphics">Graphics</a></li> <li><a class="reference internal" href="#comparison">Comparison</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="deferral"> <h2><a class="toc-backref" href="#deferral" role="doc-backlink">Deferral</a></h2> <p>While this PEP is a nice idea, no-one has yet emerged to do the work of hashing out the differences between this PEP, <a class="pep reference internal" href="../pep-0266/" title="PEP 266 – Optimizing Global Variable/Attribute Access">PEP 266</a> and <a class="pep reference internal" href="../pep-0267/" title="PEP 267 – Optimized Access to Module Namespaces">PEP 267</a>. Hence, it is being deferred.</p> </section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP describes yet another approach to optimizing access to module globals, providing an alternative to <a class="pep reference internal" href="../pep-0266/" title="PEP 266 – Optimizing Global Variable/Attribute Access">PEP 266</a> (Optimizing Global Variable/Attribute Access by Skip Montanaro) and <a class="pep reference internal" href="../pep-0267/" title="PEP 267 – Optimized Access to Module Namespaces">PEP 267</a> (Optimized Access to Module Namespaces by Jeremy Hylton).</p> <p>The expectation is that eventually one approach will be picked and implemented; possibly multiple approaches will be prototyped first.</p> </section> <section id="description"> <h2><a class="toc-backref" href="#description" role="doc-backlink">Description</a></h2> <p>(Note: Jason Orendorff writes: “””I implemented this once, long ago, for Python 1.5-ish, I believe. I got it to the point where it was only 15% slower than ordinary Python, then abandoned it. ;) In my implementation, “cells” were real first-class objects, and “celldict” was a copy-and-hack version of dictionary. I forget how the rest worked.””” Reference: <a class="reference external" href="https://mail.python.org/pipermail/python-dev/2002-February/019876.html">https://mail.python.org/pipermail/python-dev/2002-February/019876.html</a>)</p> <p>Let a cell be a really simple Python object, containing a pointer to a Python object and a pointer to a cell. Both pointers may be <code class="docutils literal notranslate"><span class="pre">NULL</span></code>. A Python implementation could be:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">cell</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="bp">self</span><span class="o">.</span><span class="n">cellptr</span> <span class="o">=</span> <span class="n">NULL</span> </pre></div> </div> <p>The cellptr attribute is used for chaining cells together for searching built-ins; this will be explained later.</p> <p>Let a celldict be a mapping from strings (the names of a module’s globals) to objects (the values of those globals), implemented using a dict of cells. A Python implementation could be:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">celldict</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># dict of cells</span> <span class="k">def</span><span class="w"> </span><span class="nf">getcell</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">c</span> <span class="o">=</span> <span class="n">cell</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span> <span class="k">return</span> <span class="n">c</span> <span class="k">def</span><span class="w"> </span><span class="nf">cellkeys</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span> <span class="k">def</span><span class="w"> </span><span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">,</span> <span class="n">key</span> <span class="n">value</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="n">NULL</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">,</span> <span class="n">key</span> <span class="k">else</span><span class="p">:</span> <span class="k">return</span> <span class="n">value</span> <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">c</span> <span class="o">=</span> <span class="n">cell</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">value</span> <span class="k">def</span><span class="w"> </span><span class="fm">__delitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="n">NULL</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">,</span> <span class="n">key</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="k">def</span><span class="w"> </span><span class="nf">keys</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="p">[</span><span class="n">k</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">items</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">preturn</span> <span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">itervalues</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">values</span><span class="p">():</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="c1"># Etc.</span> </pre></div> </div> <p>It is possible that a cell exists corresponding to a given key, but the cell’s objptr is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>; let’s call such a cell empty. When the celldict is used as a mapping, it is as if empty cells don’t exist. However, once added, a cell is never deleted from a celldict, and it is possible to get at empty cells using the <code class="docutils literal notranslate"><span class="pre">getcell()</span></code> method.</p> <p>The celldict implementation never uses the cellptr attribute of cells.</p> <p>We change the module implementation to use a celldict for its <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>. The module’s getattr, setattr and delattr operations now map to getitem, setitem and delitem on the celldict. The type of <code class="docutils literal notranslate"><span class="pre"><module>.__dict__</span></code> and <code class="docutils literal notranslate"><span class="pre">globals()</span></code> is probably the only backwards incompatibility.</p> <p>When a module is initialized, its <code class="docutils literal notranslate"><span class="pre">__builtins__</span></code> is initialized from the <code class="docutils literal notranslate"><span class="pre">__builtin__</span></code> module’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code>, which is itself a celldict. For each cell in <code class="docutils literal notranslate"><span class="pre">__builtins__</span></code>, the new module’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> adds a cell with a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> objptr, whose cellptr points to the corresponding cell of <code class="docutils literal notranslate"><span class="pre">__builtins__</span></code>. Python pseudo-code (ignoring rexec):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">__builtin__</span> <span class="k">class</span><span class="w"> </span><span class="nc">module</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span> <span class="o">=</span> <span class="n">d</span> <span class="o">=</span> <span class="n">celldict</span><span class="p">()</span> <span class="n">d</span><span class="p">[</span><span class="s1">'__builtins__'</span><span class="p">]</span> <span class="o">=</span> <span class="n">bd</span> <span class="o">=</span> <span class="n">__builtin__</span><span class="o">.</span><span class="vm">__dict__</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="n">bd</span><span class="o">.</span><span class="n">cellkeys</span><span class="p">():</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="o">.</span><span class="n">getcell</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="n">c</span><span class="o">.</span><span class="n">cellptr</span> <span class="o">=</span> <span class="n">bd</span><span class="o">.</span><span class="n">getcell</span><span class="p">(</span><span class="n">k</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="fm">__getattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">):</span> <span class="k">try</span><span class="p">:</span> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">IndexError</span><span class="p">,</span> <span class="n">k</span> <span class="k">def</span><span class="w"> </span><span class="fm">__setattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span> <span class="k">def</span><span class="w"> </span><span class="fm">__delattr__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">k</span><span class="p">):</span> <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> </pre></div> </div> <p>The compiler generates <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span> <span class="pre"><i></span></code> (and <code class="docutils literal notranslate"><span class="pre">STORE_GLOBAL_CELL</span> <span class="pre"><i></span></code> etc.) opcodes for references to globals, where <code class="docutils literal notranslate"><span class="pre"><i></span></code> is a small index with meaning only within one code object like the const index in <code class="docutils literal notranslate"><span class="pre">LOAD_CONST</span></code>. The code object has a new tuple, <code class="docutils literal notranslate"><span class="pre">co_globals</span></code>, giving the names of the globals referenced by the code indexed by <code class="docutils literal notranslate"><span class="pre"><i></span></code>. No new analysis is required to be able to do this.</p> <p>When a function object is created from a code object and a celldict, the function object creates an array of cell pointers by asking the celldict for cells corresponding to the names in the code object’s <code class="docutils literal notranslate"><span class="pre">co_globals</span></code>. If the celldict doesn’t already have a cell for a particular name, it creates and an empty one. This array of cell pointers is stored on the function object as <code class="docutils literal notranslate"><span class="pre">func_cells</span></code>. When a function object is created from a regular dict instead of a celldict, <code class="docutils literal notranslate"><span class="pre">func_cells</span></code> is a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> pointer.</p> <p>When the VM executes a <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span> <span class="pre"><i></span></code> instruction, it gets cell number <code class="docutils literal notranslate"><span class="pre"><i></span></code> from <code class="docutils literal notranslate"><span class="pre">func_cells</span></code>. It then looks in the cell’s <code class="docutils literal notranslate"><span class="pre">PyObject</span></code> pointer, and if not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, that’s the global value. If it is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, it follows the cell’s cell pointer to the next cell, if it is not <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, and looks in the <code class="docutils literal notranslate"><span class="pre">PyObject</span></code> pointer in that cell. If that’s also <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, or if there is no second cell, <code class="docutils literal notranslate"><span class="pre">NameError</span></code> is raised. (It could follow the chain of cell pointers until a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> cell pointer is found; but I have no use for this.) Similar for <code class="docutils literal notranslate"><span class="pre">STORE_GLOBAL_CELL</span> <span class="pre"><i></span></code>, except it doesn’t follow the cell pointer chain – it always stores in the first cell.</p> <p>There are fallbacks in the VM for the case where the function’s globals aren’t a celldict, and hence <code class="docutils literal notranslate"><span class="pre">func_cells</span></code> is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>. In that case, the code object’s <code class="docutils literal notranslate"><span class="pre">co_globals</span></code> is indexed with <code class="docutils literal notranslate"><span class="pre"><i></span></code> to find the name of the corresponding global and this name is used to index the function’s globals dict.</p> </section> <section id="additional-ideas"> <h2><a class="toc-backref" href="#additional-ideas" role="doc-backlink">Additional Ideas</a></h2> <ul> <li>Never make <code class="docutils literal notranslate"><span class="pre">func_cell</span></code> a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> pointer; instead, make up an array of empty cells, so that <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code> can index <code class="docutils literal notranslate"><span class="pre">func_cells</span></code> without a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> check.</li> <li>Make <code class="docutils literal notranslate"><span class="pre">c.cellptr</span></code> equal to c when a cell is created, so that <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code> can always dereference <code class="docutils literal notranslate"><span class="pre">c.cellptr</span></code> without a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> check.<p>With these two additional ideas added, here’s Python pseudo-code for <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">LOAD_GLOBAL_CELL</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">i</span><span class="p">):</span> <span class="c1"># self is the frame</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func_cells</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span><span class="p">:</span> <span class="k">return</span> <span class="n">obj</span> <span class="c1"># Existing global</span> <span class="k">return</span> <span class="n">c</span><span class="o">.</span><span class="n">cellptr</span><span class="o">.</span><span class="n">objptr</span> <span class="c1"># Built-in or NULL</span> </pre></div> </div> </li> <li>Be more aggressive: put the actual values of builtins into module dicts, not just pointers to cells containing the actual values.<p>There are two points to this: (1) Simplify and speed access, which is the most common operation. (2) Support faithful emulation of extreme existing corner cases.</p> <p>WRT #2, the set of builtins in the scheme above is captured at the time a module dict is first created. Mutations to the set of builtin names following that don’t get reflected in the module dicts. Example: consider files <code class="docutils literal notranslate"><span class="pre">main.py</span></code> and <code class="docutils literal notranslate"><span class="pre">cheater.py</span></code>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[</span><span class="n">main</span><span class="o">.</span><span class="n">py</span><span class="p">]</span> <span class="kn">import</span><span class="w"> </span><span class="nn">cheater</span> <span class="k">def</span><span class="w"> </span><span class="nf">f</span><span class="p">():</span> <span class="n">cheater</span><span class="o">.</span><span class="n">cheat</span><span class="p">()</span> <span class="k">return</span> <span class="n">pachinko</span><span class="p">()</span> <span class="nb">print</span> <span class="n">f</span><span class="p">()</span> <span class="p">[</span><span class="n">cheater</span><span class="o">.</span><span class="n">py</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">cheat</span><span class="p">():</span> <span class="kn">import</span><span class="w"> </span><span class="nn">__builtin__</span> <span class="n">__builtin__</span><span class="o">.</span><span class="n">pachinko</span> <span class="o">=</span> <span class="k">lambda</span><span class="p">:</span> <span class="mi">666</span> </pre></div> </div> <p>If <code class="docutils literal notranslate"><span class="pre">main.py</span></code> is run under Python 2.2 (or before), 666 is printed. But under the proposal, <code class="docutils literal notranslate"><span class="pre">__builtin__.pachinko</span></code> doesn’t exist at the time main’s <code class="docutils literal notranslate"><span class="pre">__dict__</span></code> is initialized. When the function object for f is created, <code class="docutils literal notranslate"><span class="pre">main.__dict__</span></code> grows a pachinko cell mapping to two <code class="docutils literal notranslate"><span class="pre">NULLs</span></code>. When <code class="docutils literal notranslate"><span class="pre">cheat()</span></code> is called, <code class="docutils literal notranslate"><span class="pre">__builtin__.__dict__</span></code> grows a pachinko cell too, but <code class="docutils literal notranslate"><span class="pre">main.__dict__</span></code> doesn’t know– and will never know –about that. When f’s return stmt references pachinko, in will still find the double-NULLs in <code class="docutils literal notranslate"><span class="pre">main.__dict__</span></code>’s <code class="docutils literal notranslate"><span class="pre">pachinko</span></code> cell, and so raise <code class="docutils literal notranslate"><span class="pre">NameError</span></code>.</p> <p>A similar (in cause) break in compatibility can occur if a module global foo is del’ed, but a builtin foo was created prior to that but after the module dict was first created. Then the builtin foo becomes visible in the module under 2.2 and before, but remains invisible under the proposal.</p> <p>Mutating builtins is extremely rare (most programs never mutate the builtins, and it’s hard to imagine a plausible use for frequent mutation of the builtins – I’ve never seen or heard of one), so it doesn’t matter how expensive mutating the builtins becomes. OTOH, referencing globals and builtins is very common. Combining those observations suggests a more aggressive caching of builtins in module globals, speeding access at the expense of making mutations of the builtins (potentially much) more expensive to keep the caches in synch.</p> <p>Much of the scheme above remains the same, and most of the rest is just a little different. A cell changes to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">cell</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">NULL</span><span class="p">,</span> <span class="n">builtin</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span> <span class="bp">self</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">obj</span> <span class="bp">self</span><span class="o">.</span><span class="n">builtinflag</span> <span class="o">=</span> <span class="n">builtin</span> </pre></div> </div> <p>and a celldict maps strings to this version of cells. <code class="docutils literal notranslate"><span class="pre">builtinflag</span></code> is true when and only when objptr contains a value obtained from the builtins; in other words, it’s true when and only when a cell is acting as a cached value. When <code class="docutils literal notranslate"><span class="pre">builtinflag</span></code> is false, objptr is the value of a module global (possibly <code class="docutils literal notranslate"><span class="pre">NULL</span></code>). celldict changes to:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">celldict</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">builtindict</span><span class="o">=</span><span class="p">()):</span> <span class="bp">self</span><span class="o">.</span><span class="n">basedict</span> <span class="o">=</span> <span class="n">builtindict</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span> <span class="o">=</span> <span class="n">d</span> <span class="o">=</span> <span class="p">{}</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">builtindict</span><span class="o">.</span><span class="n">items</span><span class="p">():</span> <span class="n">d</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">cell</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">def</span><span class="w"> </span><span class="fm">__getitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="n">NULL</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">,</span> <span class="n">key</span> <span class="k">return</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">def</span><span class="w"> </span><span class="fm">__setitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="n">c</span> <span class="o">=</span> <span class="n">cell</span><span class="p">()</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">c</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">value</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">def</span><span class="w"> </span><span class="fm">__delitem__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="n">NULL</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">:</span> <span class="k">raise</span> <span class="ne">KeyError</span><span class="p">,</span> <span class="n">key</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="c1"># We may have unmasked a builtin. Note that because</span> <span class="c1"># we're checking the builtin dict for that *now*, this</span> <span class="c1"># still works if the builtin first came into existence</span> <span class="c1"># after we were constructed. Note too that del on</span> <span class="c1"># namespace dicts is rare, so the expense of this check</span> <span class="c1"># shouldn't matter.</span> <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">basedict</span><span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">basedict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="k">assert</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span> <span class="c1"># else "in" lied</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">else</span><span class="p">:</span> <span class="c1"># There is no builtin with the same name.</span> <span class="k">assert</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="k">def</span><span class="w"> </span><span class="nf">keys</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="p">[</span><span class="n">k</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">items</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">return</span> <span class="p">[</span><span class="n">k</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">iteritems</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">values</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="n">preturn</span> <span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">itervalues</span><span class="p">()</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="ow">not</span> <span class="n">NULL</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">]</span> <span class="k">def</span><span class="w"> </span><span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">values</span><span class="p">():</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">:</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="c1"># Etc.</span> </pre></div> </div> <p>The speed benefit comes from simplifying <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code>, which I expect is executed more frequently than all other namespace operations combined:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">LOAD_GLOBAL_CELL</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">i</span><span class="p">):</span> <span class="c1"># self is the frame</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">func_cells</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="k">return</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="c1"># may be NULL (also true before)</span> </pre></div> </div> <p>That is, accessing builtins and accessing module globals are equally fast. For module globals, a NULL-pointer test+branch is saved. For builtins, an additional pointer chase is also saved.</p> <p>The other part needed to make this fly is expensive, propagating mutations of builtins into the module dicts that were initialized from the builtins. This is much like, in 2.2, propagating changes in new-style base classes to their descendants: the builtins need to maintain a list of weakrefs to the modules (or module dicts) initialized from the builtin’s dict. Given a mutation to the builtin dict (adding a new key, changing the value associated with an existing key, or deleting a key), traverse the list of module dicts and make corresponding mutations to them. This is straightforward; for example, if a key is deleted from builtins, execute <code class="docutils literal notranslate"><span class="pre">reflect_bltin_del</span></code> in each module:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">reflect_bltin_del</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">assert</span> <span class="n">c</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="c1"># else we were already out of synch</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">:</span> <span class="c1"># Put us back in synch.</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">NULL</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># Else we're shadowing the builtin, so don't care that</span> <span class="c1"># the builtin went away.</span> </pre></div> </div> <p>Note that <code class="docutils literal notranslate"><span class="pre">c.builtinflag</span></code> protects from us erroneously deleting a module global of the same name. Adding a new (key, value) builtin pair is similar:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">reflect_bltin_new</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">if</span> <span class="n">c</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># Never heard of it before: cache the builtin value.</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">cell</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="k">elif</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="ow">is</span> <span class="n">NULL</span><span class="p">:</span> <span class="c1"># This used to exist in the module or the builtins,</span> <span class="c1"># but doesn't anymore; rehabilitate it.</span> <span class="k">assert</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">value</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">else</span><span class="p">:</span> <span class="c1"># We're shadowing it already.</span> <span class="k">assert</span> <span class="ow">not</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span> </pre></div> </div> <p>Changing the value of an existing builtin:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span><span class="w"> </span><span class="nf">reflect_bltin_change</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">newvalue</span><span class="p">):</span> <span class="n">c</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">__dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">assert</span> <span class="n">c</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="c1"># else we were already out of synch</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">builtinflag</span><span class="p">:</span> <span class="c1"># Put us back in synch.</span> <span class="n">c</span><span class="o">.</span><span class="n">objptr</span> <span class="o">=</span> <span class="n">newvalue</span> <span class="c1"># Else we're shadowing the builtin, so don't care that</span> <span class="c1"># the builtin changed.</span> </pre></div> </div> </li> </ul> </section> <section id="faqs"> <h2><a class="toc-backref" href="#faqs" role="doc-backlink">FAQs</a></h2> <ul> <li>Q: Will it still be possible to:<p>a) install new builtins in the <code class="docutils literal notranslate"><span class="pre">__builtin__</span></code> namespace and have them available in all already loaded modules right away ?</p> <p>b) override builtins (e.g. <code class="docutils literal notranslate"><span class="pre">open()</span></code>) with my own copies (e.g. to increase security) in a way that makes these new copies override the previous ones in all modules ?</p> <p>A: Yes, this is the whole point of this design. In the original approach, when <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code> finds a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> in the second cell, it should go back to see if the <code class="docutils literal notranslate"><span class="pre">__builtins__</span></code> dict has been modified (the pseudo code doesn’t have this yet). Tim’s “more aggressive” alternative also takes care of this.</p> </li> <li>Q: How does the new scheme get along with the restricted execution model?<p>A: It is intended to support that fully.</p> </li> <li>Q: What happens when a global is deleted?<p>A: The module’s celldict would have a cell with a <code class="docutils literal notranslate"><span class="pre">NULL</span></code> objptr for that key. This is true in both variations, but the “aggressive” variation goes on to see whether this unmasks a builtin of the same name, and if so copies its value (just a pointer-copy of the ultimate <code class="docutils literal notranslate"><span class="pre">PyObject*</span></code>) into the cell’s objptr and sets the cell’s <code class="docutils literal notranslate"><span class="pre">builtinflag</span></code> to true.</p> </li> <li>Q: What would the C code for <code class="docutils literal notranslate"><span class="pre">LOAD_GLOBAL_CELL</span></code> look like?<p>A: The first version, with the first two bullets under “Additional ideas” incorporated, could look like this:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">LOAD_GLOBAL_CELL</span><span class="p">:</span> <span class="n">cell</span> <span class="o">=</span> <span class="n">func_cells</span><span class="p">[</span><span class="n">oparg</span><span class="p">];</span> <span class="n">x</span> <span class="o">=</span> <span class="n">cell</span><span class="o">-></span><span class="n">objptr</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="n">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">x</span> <span class="o">=</span> <span class="n">cell</span><span class="o">-></span><span class="n">cellptr</span><span class="o">-></span><span class="n">objptr</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">==</span> <span class="n">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="n">error</span> <span class="n">recovery</span> <span class="o">...</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="n">PUSH</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="k">continue</span><span class="p">;</span> </pre></div> </div> <p>We could even write it like this (idea courtesy of Ka-Ping Yee):</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">LOAD_GLOBAL_CELL</span><span class="p">:</span> <span class="n">cell</span> <span class="o">=</span> <span class="n">func_cells</span><span class="p">[</span><span class="n">oparg</span><span class="p">];</span> <span class="n">x</span> <span class="o">=</span> <span class="n">cell</span><span class="o">-></span><span class="n">cellptr</span><span class="o">-></span><span class="n">objptr</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="n">PUSH</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="k">continue</span><span class="p">;</span> <span class="p">}</span> <span class="o">...</span> <span class="n">error</span> <span class="n">recovery</span> <span class="o">...</span> <span class="k">break</span><span class="p">;</span> </pre></div> </div> <p>In modern CPU architectures, this reduces the number of branches taken for built-ins, which might be a really good thing, while any decent memory cache should realize that <code class="docutils literal notranslate"><span class="pre">cell->cellptr</span></code> is the same as cell for regular globals and hence this should be very fast in that case too.</p> <p>For the aggressive variant:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">case</span> <span class="n">LOAD_GLOBAL_CELL</span><span class="p">:</span> <span class="n">cell</span> <span class="o">=</span> <span class="n">func_cells</span><span class="p">[</span><span class="n">oparg</span><span class="p">];</span> <span class="n">x</span> <span class="o">=</span> <span class="n">cell</span><span class="o">-></span><span class="n">objptr</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span><span class="n">x</span> <span class="o">!=</span> <span class="n">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">Py_INCREF</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="n">PUSH</span><span class="p">(</span><span class="n">x</span><span class="p">);</span> <span class="k">continue</span><span class="p">;</span> <span class="p">}</span> <span class="o">...</span> <span class="n">error</span> <span class="n">recovery</span> <span class="o">...</span> <span class="k">break</span><span class="p">;</span> </pre></div> </div> </li> <li>Q: What happens in the module’s top-level code where there is presumably no <code class="docutils literal notranslate"><span class="pre">func_cells</span></code> array?<p>A: We could do some code analysis and create a <code class="docutils literal notranslate"><span class="pre">func_cells</span></code> array, or we could use <code class="docutils literal notranslate"><span class="pre">LOAD_NAME</span></code> which should use <code class="docutils literal notranslate"><span class="pre">PyMapping_GetItem</span></code> on the globals dict.</p> </li> </ul> </section> <section id="graphics"> <h2><a class="toc-backref" href="#graphics" role="doc-backlink">Graphics</a></h2> <p>Ka-Ping Yee supplied a drawing of the state of things after “import spam”, where <code class="docutils literal notranslate"><span class="pre">spam.py</span></code> contains:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span><span class="w"> </span><span class="nn">eggs</span> <span class="n">i</span> <span class="o">=</span> <span class="o">-</span><span class="mi">2</span> <span class="nb">max</span> <span class="o">=</span> <span class="mi">3</span> <span class="k">def</span><span class="w"> </span><span class="nf">foo</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="n">y</span> <span class="o">=</span> <span class="nb">abs</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="o">+</span> <span class="nb">max</span> <span class="k">return</span> <span class="n">eggs</span><span class="o">.</span><span class="n">ham</span><span class="p">(</span><span class="n">y</span> <span class="o">+</span> <span class="n">n</span><span class="p">)</span> </pre></div> </div> <p>The drawing is at <a class="reference external" href="http://web.lfw.org/repo/cells.gif">http://web.lfw.org/repo/cells.gif</a>; a larger version is at <a class="reference external" href="http://lfw.org/repo/cells-big.gif">http://lfw.org/repo/cells-big.gif</a>; the source is at <a class="reference external" href="http://lfw.org/repo/cells.ai">http://lfw.org/repo/cells.ai</a>.</p> </section> <section id="comparison"> <h2><a class="toc-backref" href="#comparison" role="doc-backlink">Comparison</a></h2> <p>XXX Here, a comparison of the three approaches could be added.</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document has been placed in the public domain.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0280.rst">https://github.com/python/peps/blob/main/peps/pep-0280.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0280.rst">2025-02-01 08:55:40 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#deferral">Deferral</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#description">Description</a></li> <li><a class="reference internal" href="#additional-ideas">Additional Ideas</a></li> <li><a class="reference internal" href="#faqs">FAQs</a></li> <li><a class="reference internal" href="#graphics">Graphics</a></li> <li><a class="reference internal" href="#comparison">Comparison</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-0280.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>