python-peps/pep-0280/index.html

619 lines
62 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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> &raquo; </li>
<li><a href="../pep-0000/">PEP Index</a> &raquo; </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 &lt;guido&#32;&#97;t&#32;python.org&gt;</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="nc">cell</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</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 modules
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="nc">celldict</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</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="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="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="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="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="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="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="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="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="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 cells objptr is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>; lets call such a cell empty. When
the celldict is used as a mapping, it is as if empty cells dont
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 modules 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">&lt;module&gt;.__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> modules <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 modules <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="nn">__builtin__</span>
<span class="k">class</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="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">&#39;__builtins__&#39;</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="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="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="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">&lt;i&gt;</span></code> (and <code class="docutils literal notranslate"><span class="pre">STORE_GLOBAL_CELL</span>
<span class="pre">&lt;i&gt;</span></code> etc.) opcodes for references to globals, where <code class="docutils literal notranslate"><span class="pre">&lt;i&gt;</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">&lt;i&gt;</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 objects
<code class="docutils literal notranslate"><span class="pre">co_globals</span></code>. If the celldict doesnt 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">&lt;i&gt;</span></code> instruction, it gets
cell number <code class="docutils literal notranslate"><span class="pre">&lt;i&gt;</span></code> from <code class="docutils literal notranslate"><span class="pre">func_cells</span></code>. It then looks in the cells
<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>, thats the global value. If it
is <code class="docutils literal notranslate"><span class="pre">NULL</span></code>, it follows the cells 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
thats 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">&lt;i&gt;</span></code>, except it doesnt 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 functions
globals arent 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 objects <code class="docutils literal notranslate"><span class="pre">co_globals</span></code> is indexed with <code class="docutils literal notranslate"><span class="pre">&lt;i&gt;</span></code> to find the
name of the corresponding global and this name is used to index the
functions 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, heres 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="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 dont 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="nn">cheater</span>
<span class="k">def</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="nf">cheat</span><span class="p">():</span>
<span class="kn">import</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> doesnt exist at the time
mains <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> doesnt know and will never know about
that. When fs 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 deled, 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 its hard to imagine a plausible use for frequent
mutation of the builtins Ive never seen or heard of one), so it
doesnt 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="nc">cell</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</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, its 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="nc">celldict</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</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="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="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="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&#39;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&#39;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 &quot;in&quot; 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="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="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="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="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="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 builtins 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="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&#39;re shadowing the builtin, so don&#39;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="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&#39;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&#39;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="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&#39;re shadowing the builtin, so don&#39;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 doesnt have this yet). Tims
“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 modules 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 cells objptr and sets the cells
<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">-&gt;</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">-&gt;</span><span class="n">cellptr</span><span class="o">-&gt;</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">-&gt;</span><span class="n">cellptr</span><span class="o">-&gt;</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-&gt;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">-&gt;</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 modules 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="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="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">2023-09-09 17:39:29 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>