python-peps/pep-3104/index.html

706 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 3104 Access to Names in Outer Scopes | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-3104/">
<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 3104 Access to Names in Outer Scopes | peps.python.org'>
<meta property="og:description" content="In most languages that support nested scopes, code can refer to or rebind (assign to) any name in the nearest enclosing scope. Currently, Python code can refer to a name in any enclosing scope, but it can only rebind names in two scopes: the local scope...">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-3104/">
<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="In most languages that support nested scopes, code can refer to or rebind (assign to) any name in the nearest enclosing scope. Currently, Python code can refer to a name in any enclosing scope, but it can only rebind names in two scopes: the local scope...">
<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 3104</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 3104 Access to Names in Outer Scopes</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Ka-Ping Yee &lt;ping&#32;&#97;t&#32;zesty.ca&gt;</dd>
<dt class="field-even">Status<span class="colon">:</span></dt>
<dd class="field-even"><abbr title="Accepted and implementation complete, or no longer active">Final</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">12-Oct-2006</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">3.0</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="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#other-languages">Other Languages</a><ul>
<li><a class="reference internal" href="#javascript-perl-scheme-smalltalk-gnu-c-c-2-0">JavaScript, Perl, Scheme, Smalltalk, GNU C, C# 2.0</a></li>
<li><a class="reference internal" href="#ruby-as-of-1-8">Ruby (as of 1.8)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#overview-of-proposals">Overview of Proposals</a><ul>
<li><a class="reference internal" href="#new-syntax-in-the-binding-outer-scope">New Syntax in the Binding (Outer) Scope</a><ul>
<li><a class="reference internal" href="#scope-override-declaration">Scope Override Declaration</a></li>
<li><a class="reference internal" href="#required-variable-declaration">Required Variable Declaration</a></li>
</ul>
</li>
<li><a class="reference internal" href="#new-syntax-in-the-referring-inner-scope">New Syntax in the Referring (Inner) Scope</a><ul>
<li><a class="reference internal" href="#outer-reference-expression">Outer Reference Expression</a></li>
<li><a class="reference internal" href="#rebinding-operator">Rebinding Operator</a></li>
<li><a class="reference internal" href="#id15">Scope Override Declaration</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#proposed-solution">Proposed Solution</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>In most languages that support nested scopes, code can refer to or
rebind (assign to) any name in the nearest enclosing scope.
Currently, Python code can refer to a name in any enclosing scope,
but it can only rebind names in two scopes: the local scope (by
simple assignment) or the module-global scope (using a <code class="docutils literal notranslate"><span class="pre">global</span></code>
declaration).</p>
<p>This limitation has been raised many times on the Python-Dev mailing
list and elsewhere, and has led to extended discussion and many
proposals for ways to remove this limitation. This PEP summarizes
the various alternatives that have been suggested, together with
advantages and disadvantages that have been mentioned for each.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>Before version 2.1, Pythons treatment of scopes resembled that of
standard C: within a file there were only two levels of scope, global
and local. In C, this is a natural consequence of the fact that
function definitions cannot be nested. But in Python, though
functions are usually defined at the top level, a function definition
can be executed anywhere. This gave Python the syntactic appearance
of nested scoping without the semantics, and yielded inconsistencies
that were surprising to some programmers for example, a recursive
function that worked at the top level would cease to work when moved
inside another function, because the recursive functions own name
would no longer be visible in its bodys scope. This violates the
intuition that a function should behave consistently when placed in
different contexts. Heres an example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">enclosing_function</span><span class="p">():</span>
<span class="k">def</span> <span class="nf">factorial</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="k">return</span> <span class="n">n</span> <span class="o">*</span> <span class="n">factorial</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="c1"># fails with NameError</span>
<span class="nb">print</span> <span class="n">factorial</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
</pre></div>
</div>
<p>Python 2.1 moved closer to static nested scoping by making visible
the names bound in all enclosing scopes (see <a class="pep reference internal" href="../pep-0227/" title="PEP 227 Statically Nested Scopes">PEP 227</a>). This change
makes the above code example work as expected. However, because any
assignment to a name implicitly declares that name to be local, it is
impossible to rebind a name in an outer scope (except when a
<code class="docutils literal notranslate"><span class="pre">global</span></code> declaration forces the name to be global). Thus, the
following code, intended to display a number that can be incremented
and decremented by clicking buttons, doesnt work as someone familiar
with lexical scoping might expect:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">make_scoreboard</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">score</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">Label</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span>
<span class="n">label</span><span class="o">.</span><span class="n">pack</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">]:</span>
<span class="k">def</span> <span class="nf">increment</span><span class="p">(</span><span class="n">step</span><span class="o">=</span><span class="n">i</span><span class="p">):</span>
<span class="n">score</span> <span class="o">=</span> <span class="n">score</span> <span class="o">+</span> <span class="n">step</span> <span class="c1"># fails with UnboundLocalError</span>
<span class="n">label</span><span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">score</span>
<span class="n">button</span> <span class="o">=</span> <span class="n">Button</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%+d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">i</span><span class="p">,</span> <span class="n">command</span><span class="o">=</span><span class="n">increment</span><span class="p">)</span>
<span class="n">button</span><span class="o">.</span><span class="n">pack</span><span class="p">()</span>
<span class="k">return</span> <span class="n">label</span>
</pre></div>
</div>
<p>Python syntax doesnt provide a way to indicate that the name
<code class="docutils literal notranslate"><span class="pre">score</span></code> mentioned in <code class="docutils literal notranslate"><span class="pre">increment</span></code> refers to the variable <code class="docutils literal notranslate"><span class="pre">score</span></code>
bound in <code class="docutils literal notranslate"><span class="pre">make_scoreboard</span></code>, not a local variable in <code class="docutils literal notranslate"><span class="pre">increment</span></code>.
Users and developers of Python have expressed an interest in removing
this limitation so that Python can have the full flexibility of the
Algol-style scoping model that is now standard in many programming
languages, including JavaScript, Perl, Ruby, Scheme, Smalltalk,
C with GNU extensions, and C# 2.0.</p>
<p>It has been argued that such a feature isnt necessary, because
a rebindable outer variable can be simulated by wrapping it in a
mutable object:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">Namespace</span><span class="p">:</span>
<span class="k">pass</span>
<span class="k">def</span> <span class="nf">make_scoreboard</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">score</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
<span class="n">ns</span> <span class="o">=</span> <span class="n">Namespace</span><span class="p">()</span>
<span class="n">ns</span><span class="o">.</span><span class="n">score</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">label</span> <span class="o">=</span> <span class="n">Label</span><span class="p">(</span><span class="n">frame</span><span class="p">)</span>
<span class="n">label</span><span class="o">.</span><span class="n">pack</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="p">[</span><span class="o">-</span><span class="mi">10</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">10</span><span class="p">]:</span>
<span class="k">def</span> <span class="nf">increment</span><span class="p">(</span><span class="n">step</span><span class="o">=</span><span class="n">i</span><span class="p">):</span>
<span class="n">ns</span><span class="o">.</span><span class="n">score</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">score</span> <span class="o">+</span> <span class="n">step</span>
<span class="n">label</span><span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ns</span><span class="o">.</span><span class="n">score</span>
<span class="n">button</span> <span class="o">=</span> <span class="n">Button</span><span class="p">(</span><span class="n">frame</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s1">&#39;</span><span class="si">%+d</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">i</span><span class="p">,</span> <span class="n">command</span><span class="o">=</span><span class="n">increment</span><span class="p">)</span>
<span class="n">button</span><span class="o">.</span><span class="n">pack</span><span class="p">()</span>
<span class="k">return</span> <span class="n">label</span>
</pre></div>
</div>
<p>However, this workaround only highlights the shortcomings of existing
scopes: the purpose of a function is to encapsulate code in its own
namespace, so it seems unfortunate that the programmer should have to
create additional namespaces to make up for missing functionality in
the existing local scopes, and then have to decide whether each name
should reside in the real scope or the simulated scope.</p>
<p>Another common objection is that the desired functionality can be
written as a class instead, albeit somewhat more verbosely. One
rebuttal to this objection is that the existence of a different
implementation style is not a reason to leave a supported programming
construct (nested scopes) functionally incomplete. Python is
sometimes called a “multi-paradigm language” because it derives so
much strength, practical flexibility, and pedagogical power from its
support and graceful integration of multiple programming paradigms.</p>
<p>A proposal for scoping syntax appeared on Python-Dev as far back as
1994 <a class="footnote-reference brackets" href="#id45" id="id1">[1]</a>, long before <a class="pep reference internal" href="../pep-0227/" title="PEP 227 Statically Nested Scopes">PEP 227</a>s support for nested scopes was
adopted. At the time, Guidos response was:</p>
<blockquote>
<div>This is dangerously close to introducing CSNS [classic static
nested scopes]. <em>If</em> you were to do so, your proposed semantics
of scoped seem alright. I still think there is not enough need
for CSNS to warrant this kind of construct …</div></blockquote>
<p>After <a class="pep reference internal" href="../pep-0227/" title="PEP 227 Statically Nested Scopes">PEP 227</a>, the “outer name rebinding discussion” has reappeared
on Python-Dev enough times that it has become a familiar event,
having recurred in its present form since at least 2003 <a class="footnote-reference brackets" href="#id46" id="id2">[2]</a>.
Although none of the language changes proposed in these discussions
have yet been adopted, Guido has acknowledged that a language change
is worth considering <a class="footnote-reference brackets" href="#id56" id="id3">[12]</a>.</p>
</section>
<section id="other-languages">
<h2><a class="toc-backref" href="#other-languages" role="doc-backlink">Other Languages</a></h2>
<p>To provide some background, this section describes how some other
languages handle nested scopes and rebinding.</p>
<section id="javascript-perl-scheme-smalltalk-gnu-c-c-2-0">
<h3><a class="toc-backref" href="#javascript-perl-scheme-smalltalk-gnu-c-c-2-0" role="doc-backlink">JavaScript, Perl, Scheme, Smalltalk, GNU C, C# 2.0</a></h3>
<p>These languages use variable declarations to indicate scope. In
JavaScript, a lexically scoped variable is declared with the <code class="docutils literal notranslate"><span class="pre">var</span></code>
keyword; undeclared variable names are assumed to be global. In
Perl, a lexically scoped variable is declared with the <code class="docutils literal notranslate"><span class="pre">my</span></code>
keyword; undeclared variable names are assumed to be global. In
Scheme, all variables must be declared (with <code class="docutils literal notranslate"><span class="pre">define</span></code> or <code class="docutils literal notranslate"><span class="pre">let</span></code>,
or as formal parameters). In Smalltalk, any block can begin by
declaring a list of local variable names between vertical bars.
C and C# require type declarations for all variables. For all these
cases, the variable belongs to the scope containing the declaration.</p>
</section>
<section id="ruby-as-of-1-8">
<h3><a class="toc-backref" href="#ruby-as-of-1-8" role="doc-backlink">Ruby (as of 1.8)</a></h3>
<p>Ruby is an instructive example because it appears to be the only
other currently popular language that, like Python, tries to support
statically nested scopes without requiring variable declarations, and
thus has to come up with an unusual solution. Functions in Ruby can
contain other function definitions, and they can also contain code
blocks enclosed in curly braces. Blocks have access to outer
variables, but nested functions do not. Within a block, an
assignment to a name implies a declaration of a local variable only
if it would not shadow a name already bound in an outer scope;
otherwise assignment is interpreted as rebinding of the outer name.
Rubys scoping syntax and rules have also been debated at great
length, and changes seem likely in Ruby 2.0 <a class="footnote-reference brackets" href="#id71" id="id4">[28]</a>.</p>
</section>
</section>
<section id="overview-of-proposals">
<h2><a class="toc-backref" href="#overview-of-proposals" role="doc-backlink">Overview of Proposals</a></h2>
<p>There have been many different proposals on Python-Dev for ways to
rebind names in outer scopes. They all fall into two categories:
new syntax in the scope where the name is bound, or new syntax in
the scope where the name is used.</p>
<section id="new-syntax-in-the-binding-outer-scope">
<h3><a class="toc-backref" href="#new-syntax-in-the-binding-outer-scope" role="doc-backlink">New Syntax in the Binding (Outer) Scope</a></h3>
<section id="scope-override-declaration">
<h4><a class="toc-backref" href="#scope-override-declaration" role="doc-backlink">Scope Override Declaration</a></h4>
<p>The proposals in this category all suggest a new kind of declaration
statement similar to JavaScripts <code class="docutils literal notranslate"><span class="pre">var</span></code>. A few possible keywords
have been proposed for this purpose:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">scope</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id48" id="id5">[4]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">var</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id48" id="id6">[4]</a> <a class="footnote-reference brackets" href="#id53" id="id7">[9]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">my</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id57" id="id8">[13]</a></li>
</ul>
<p>In all these proposals, a declaration such as <code class="docutils literal notranslate"><span class="pre">var</span> <span class="pre">x</span></code> in a
particular scope S would cause all references to <code class="docutils literal notranslate"><span class="pre">x</span></code> in scopes
nested within S to refer to the <code class="docutils literal notranslate"><span class="pre">x</span></code> bound in S.</p>
<p>The primary objection to this category of proposals is that the
meaning of a function definition would become context-sensitive.
Moving a function definition inside some other block could cause any
of the local name references in the function to become nonlocal, due
to declarations in the enclosing block. For blocks in Ruby 1.8,
this is actually the case; in the following example, the two setters
have different effects even though they look identical:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">setter1</span> <span class="o">=</span> <span class="n">proc</span> <span class="p">{</span> <span class="o">|</span> <span class="n">x</span> <span class="o">|</span> <span class="n">y</span> <span class="o">=</span> <span class="n">x</span> <span class="p">}</span> <span class="c1"># y is local here</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">13</span>
<span class="n">setter2</span> <span class="o">=</span> <span class="n">proc</span> <span class="p">{</span> <span class="o">|</span> <span class="n">x</span> <span class="o">|</span> <span class="n">y</span> <span class="o">=</span> <span class="n">x</span> <span class="p">}</span> <span class="c1"># y is nonlocal here</span>
<span class="n">setter1</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">99</span><span class="p">)</span>
<span class="n">puts</span> <span class="n">y</span> <span class="c1"># prints 13</span>
<span class="n">setter2</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="mi">77</span><span class="p">)</span>
<span class="n">puts</span> <span class="n">y</span> <span class="c1"># prints 77</span>
</pre></div>
</div>
<p>Note that although this proposal resembles declarations in JavaScript
and Perl, the effect on the language is different because in those
languages undeclared variables are global by default, whereas in
Python undeclared variables are local by default. Thus, moving
a function inside some other block in JavaScript or Perl can only
reduce the scope of a previously global name reference, whereas in
Python with this proposal, it could expand the scope of a previously
local name reference.</p>
</section>
<section id="required-variable-declaration">
<h4><a class="toc-backref" href="#required-variable-declaration" role="doc-backlink">Required Variable Declaration</a></h4>
<p>A more radical proposal <a class="footnote-reference brackets" href="#id64" id="id9">[21]</a> suggests removing Pythons scope-guessing
convention altogether and requiring that all names be declared in the
scope where they are to be bound, much like Scheme. With this
proposal, <code class="docutils literal notranslate"><span class="pre">var</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">3</span></code> would both declare <code class="docutils literal notranslate"><span class="pre">x</span></code> to belong to the
local scope and bind it, where as <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">3</span></code> would rebind the existing
visible <code class="docutils literal notranslate"><span class="pre">x</span></code>. In a context without an enclosing scope containing a
<code class="docutils literal notranslate"><span class="pre">var</span> <span class="pre">x</span></code> declaration, the statement <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">3</span></code> would be statically
determined to be illegal.</p>
<p>This proposal yields a simple and consistent model, but it would be
incompatible with all existing Python code.</p>
</section>
</section>
<section id="new-syntax-in-the-referring-inner-scope">
<h3><a class="toc-backref" href="#new-syntax-in-the-referring-inner-scope" role="doc-backlink">New Syntax in the Referring (Inner) Scope</a></h3>
<p>There are three kinds of proposals in this category.</p>
<section id="outer-reference-expression">
<h4><a class="toc-backref" href="#outer-reference-expression" role="doc-backlink">Outer Reference Expression</a></h4>
<p>This type of proposal suggests a new way of referring to a variable
in an outer scope when using the variable in an expression. One
syntax that has been suggested for this is <code class="docutils literal notranslate"><span class="pre">.x</span></code> <a class="footnote-reference brackets" href="#id51" id="id10">[7]</a>, which would
refer to <code class="docutils literal notranslate"><span class="pre">x</span></code> without creating a local binding for it. A concern
with this proposal is that in many contexts <code class="docutils literal notranslate"><span class="pre">x</span></code> and <code class="docutils literal notranslate"><span class="pre">.x</span></code> could
be used interchangeably, which would confuse the reader <a class="footnote-reference brackets" href="#id74" id="id11">[31]</a>. A
closely related idea is to use multiple dots to specify the number
of scope levels to ascend <a class="footnote-reference brackets" href="#id52" id="id12">[8]</a>, but most consider this too error-prone
<a class="footnote-reference brackets" href="#id60" id="id13">[17]</a>.</p>
</section>
<section id="rebinding-operator">
<h4><a class="toc-backref" href="#rebinding-operator" role="doc-backlink">Rebinding Operator</a></h4>
<p>This proposal suggests a new assignment-like operator that rebinds
a name without declaring the name to be local <a class="footnote-reference brackets" href="#id46" id="id14">[2]</a>. Whereas the
statement <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">=</span> <span class="pre">3</span></code> both declares <code class="docutils literal notranslate"><span class="pre">x</span></code> a local variable and binds
it to 3, the statement <code class="docutils literal notranslate"><span class="pre">x</span> <span class="pre">:=</span> <span class="pre">3</span></code> would change the existing binding
of <code class="docutils literal notranslate"><span class="pre">x</span></code> without declaring it local.</p>
<p>This is a simple solution, but according to <a class="pep reference internal" href="../pep-3099/" title="PEP 3099 Things that will Not Change in Python 3000">PEP 3099</a> it has been
rejected (perhaps because it would be too easy to miss or to confuse
with <code class="docutils literal notranslate"><span class="pre">=</span></code>).</p>
</section>
<section id="id15">
<h4><a class="toc-backref" href="#id15" role="doc-backlink">Scope Override Declaration</a></h4>
<p>The proposals in this category suggest a new kind of declaration
statement in the inner scope that prevents a name from becoming
local. This statement would be similar in nature to the <code class="docutils literal notranslate"><span class="pre">global</span></code>
statement, but instead of making the name refer to a binding in the
top module-level scope, it would make the name refer to the binding
in the nearest enclosing scope.</p>
<p>This approach is attractive due to its parallel with a familiar
Python construct, and because it retains context-independence for
function definitions.</p>
<p>This approach also has advantages from a security and debugging
perspective. The resulting Python would not only match the
functionality of other nested-scope languages but would do so with a
syntax that is arguably even better for defensive programming. In
most other languages, a declaration contracts the scope of an
existing name, so inadvertently omitting the declaration could yield
farther-reaching (i.e. more dangerous) effects than expected. In
Python with this proposal, the extra effort of adding the declaration
is aligned with the increased risk of non-local effects (i.e. the
path of least resistance is the safer path).</p>
<p>Many spellings have been suggested for such a declaration:</p>
<ul class="simple">
<li><code class="docutils literal notranslate"><span class="pre">scoped</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id45" id="id16">[1]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">global</span> <span class="pre">x</span> <span class="pre">in</span> <span class="pre">f</span></code> <a class="footnote-reference brackets" href="#id47" id="id17">[3]</a> (explicitly specify which scope)</li>
<li><code class="docutils literal notranslate"><span class="pre">free</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id49" id="id18">[5]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">outer</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id50" id="id19">[6]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">use</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id53" id="id20">[9]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">global</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id54" id="id21">[10]</a> (change the meaning of <code class="docutils literal notranslate"><span class="pre">global</span></code>)</li>
<li><code class="docutils literal notranslate"><span class="pre">nonlocal</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id55" id="id22">[11]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">global</span> <span class="pre">x</span> <span class="pre">outer</span></code> <a class="footnote-reference brackets" href="#id61" id="id23">[18]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">global</span> <span class="pre">in</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id61" id="id24">[18]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">not</span> <span class="pre">global</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id61" id="id25">[18]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">extern</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id63" id="id26">[20]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">ref</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id27">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">refer</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id28">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">share</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id29">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">sharing</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id30">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">common</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id31">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">using</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id32">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">borrow</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id65" id="id33">[22]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">reuse</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id66" id="id34">[23]</a></li>
<li><code class="docutils literal notranslate"><span class="pre">scope</span> <span class="pre">f</span> <span class="pre">x</span></code> <a class="footnote-reference brackets" href="#id68" id="id35">[25]</a> (explicitly specify which scope)</li>
</ul>
<p>The most commonly discussed choices appear to be <code class="docutils literal notranslate"><span class="pre">outer</span></code>,
<code class="docutils literal notranslate"><span class="pre">global</span></code>, and <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code>. <code class="docutils literal notranslate"><span class="pre">outer</span></code> is already used as both a
variable name and an attribute name in the standard library. The
word <code class="docutils literal notranslate"><span class="pre">global</span></code> has a conflicting meaning, because “global variable”
is generally understood to mean a variable with top-level scope <a class="footnote-reference brackets" href="#id70" id="id36">[27]</a>.
In C, the keyword <code class="docutils literal notranslate"><span class="pre">extern</span></code> means that a name refers to a variable
in a different compilation unit. While <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> is a bit long
and less pleasant-sounding than some of the other options, it does
have precisely the correct meaning: it declares a name not local.</p>
</section>
</section>
</section>
<section id="proposed-solution">
<h2><a class="toc-backref" href="#proposed-solution" role="doc-backlink">Proposed Solution</a></h2>
<p>The solution proposed by this PEP is to add a scope override
declaration in the referring (inner) scope. Guido has expressed a
preference for this category of solution on Python-Dev <a class="footnote-reference brackets" href="#id58" id="id37">[14]</a> and has
shown approval for <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> as the keyword <a class="footnote-reference brackets" href="#id62" id="id38">[19]</a>.</p>
<p>The proposed declaration:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">nonlocal</span> <span class="n">x</span>
</pre></div>
</div>
<p>prevents <code class="docutils literal notranslate"><span class="pre">x</span></code> from becoming a local name in the current scope. All
occurrences of <code class="docutils literal notranslate"><span class="pre">x</span></code> in the current scope will refer to the <code class="docutils literal notranslate"><span class="pre">x</span></code>
bound in an outer enclosing scope. As with <code class="docutils literal notranslate"><span class="pre">global</span></code>, multiple
names are permitted:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">nonlocal</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">z</span>
</pre></div>
</div>
<p>If there is no pre-existing binding in an enclosing scope, the
compiler raises a SyntaxError. (It may be a bit of a stretch to
call this a syntax error, but so far SyntaxError is used for all
compile-time errors, including, for example, __future__ import
with an unknown feature name.) Guido has said that this kind of
declaration in the absence of an outer binding should be considered
an error <a class="footnote-reference brackets" href="#id59" id="id39">[16]</a>.</p>
<p>If a <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> declaration collides with the name of a formal
parameter in the local scope, the compiler raises a SyntaxError.</p>
<p>A shorthand form is also permitted, in which <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> is
prepended to an assignment or augmented assignment:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">nonlocal</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">3</span>
</pre></div>
</div>
<p>The above has exactly the same meaning as <code class="docutils literal notranslate"><span class="pre">nonlocal</span> <span class="pre">x;</span> <span class="pre">x</span> <span class="pre">=</span> <span class="pre">3</span></code>.
(Guido supports a similar form of the <code class="docutils literal notranslate"><span class="pre">global</span></code> statement <a class="footnote-reference brackets" href="#id67" id="id40">[24]</a>.)</p>
<p>On the left side of the shorthand form, only identifiers are allowed,
not target expressions like <code class="docutils literal notranslate"><span class="pre">x[0]</span></code>. Otherwise, all forms of
assignment are allowed. The proposed grammar of the <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code>
statement is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">nonlocal_stmt</span> <span class="p">:</span><span class="o">:=</span>
<span class="s2">&quot;nonlocal&quot;</span> <span class="n">identifier</span> <span class="p">(</span><span class="s2">&quot;,&quot;</span> <span class="n">identifier</span><span class="p">)</span><span class="o">*</span>
<span class="p">[</span><span class="s2">&quot;=&quot;</span> <span class="p">(</span><span class="n">target_list</span> <span class="s2">&quot;=&quot;</span><span class="p">)</span><span class="o">+</span> <span class="n">expression_list</span><span class="p">]</span>
<span class="o">|</span> <span class="s2">&quot;nonlocal&quot;</span> <span class="n">identifier</span> <span class="n">augop</span> <span class="n">expression_list</span>
</pre></div>
</div>
<p>The rationale for allowing all these forms of assignment is that it
simplifies understanding of the <code class="docutils literal notranslate"><span class="pre">nonlocal</span></code> statement. Separating
the shorthand form into a declaration and an assignment is sufficient
to understand what it means and whether it is valid.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The shorthand syntax was not added in the original implementation
of the PEP. Later discussions <a class="footnote-reference brackets" href="#id72" id="id41">[29]</a> <a class="footnote-reference brackets" href="#id73" id="id42">[30]</a> concluded this syntax
should not be implemented.</p>
</div>
</section>
<section id="backward-compatibility">
<h2><a class="toc-backref" href="#backward-compatibility" role="doc-backlink">Backward Compatibility</a></h2>
<p>This PEP targets Python 3000, as suggested by Guido <a class="footnote-reference brackets" href="#id62" id="id43">[19]</a>. However,
others have noted that some options considered in this PEP may be
small enough changes to be feasible in Python 2.x <a class="footnote-reference brackets" href="#id69" id="id44">[26]</a>, in which
case this PEP could possibly be moved to be a 2.x series PEP.</p>
<p>As a (very rough) measure of the impact of introducing a new keyword,
here is the number of times that some of the proposed keywords appear
as identifiers in the standard library, according to a scan of the
Python SVN repository on November 5, 2006:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">nonlocal</span> <span class="mi">0</span>
<span class="n">use</span> <span class="mi">2</span>
<span class="n">using</span> <span class="mi">3</span>
<span class="n">reuse</span> <span class="mi">4</span>
<span class="n">free</span> <span class="mi">8</span>
<span class="n">outer</span> <span class="mi">147</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">global</span></code> appears 214 times as an existing keyword. As a measure
of the impact of using <code class="docutils literal notranslate"><span class="pre">global</span></code> as the outer-scope keyword, there
are 18 files in the standard library that would break as a result
of such a change (because a function declares a variable <code class="docutils literal notranslate"><span class="pre">global</span></code>
before that variable has been introduced in the global scope):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cgi</span><span class="o">.</span><span class="n">py</span>
<span class="n">dummy_thread</span><span class="o">.</span><span class="n">py</span>
<span class="n">mhlib</span><span class="o">.</span><span class="n">py</span>
<span class="n">mimetypes</span><span class="o">.</span><span class="n">py</span>
<span class="n">idlelib</span><span class="o">/</span><span class="n">PyShell</span><span class="o">.</span><span class="n">py</span>
<span class="n">idlelib</span><span class="o">/</span><span class="n">run</span><span class="o">.</span><span class="n">py</span>
<span class="n">msilib</span><span class="o">/</span><span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">inspect_fodder</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_compiler</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_decimal</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_descr</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_dummy_threading</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_fileinput</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_global</span><span class="o">.</span><span class="n">py</span> <span class="p">(</span><span class="ow">not</span> <span class="n">counted</span><span class="p">:</span> <span class="n">this</span> <span class="n">tests</span> <span class="n">the</span> <span class="n">keyword</span> <span class="n">itself</span><span class="p">)</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_grammar</span><span class="o">.</span><span class="n">py</span> <span class="p">(</span><span class="ow">not</span> <span class="n">counted</span><span class="p">:</span> <span class="n">this</span> <span class="n">tests</span> <span class="n">the</span> <span class="n">keyword</span> <span class="n">itself</span><span class="p">)</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_itertools</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_multifile</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_scope</span><span class="o">.</span><span class="n">py</span> <span class="p">(</span><span class="ow">not</span> <span class="n">counted</span><span class="p">:</span> <span class="n">this</span> <span class="n">tests</span> <span class="n">the</span> <span class="n">keyword</span> <span class="n">itself</span><span class="p">)</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_threaded_import</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_threadsignals</span><span class="o">.</span><span class="n">py</span>
<span class="n">test</span><span class="o">/</span><span class="n">test_warnings</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id45" role="doc-footnote">
<dt class="label" id="id45">[1]<em> (<a href='#id1'>1</a>, <a href='#id16'>2</a>) </em></dt>
<dd>Scoping (was Re: Lambda binding solved?) (Rafael Bracho)
<a class="reference external" href="https://legacy.python.org/search/hypermail/python-1994q1/0301.html">https://legacy.python.org/search/hypermail/python-1994q1/0301.html</a></aside>
<aside class="footnote brackets" id="id46" role="doc-footnote">
<dt class="label" id="id46">[2]<em> (<a href='#id2'>1</a>, <a href='#id14'>2</a>) </em></dt>
<dd>Extended Function syntax (Just van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2003-February/032764.html">https://mail.python.org/pipermail/python-dev/2003-February/032764.html</a></aside>
<aside class="footnote brackets" id="id47" role="doc-footnote">
<dt class="label" id="id47">[<a href="#id17">3</a>]</dt>
<dd>Closure semantics (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2003-October/039214.html">https://mail.python.org/pipermail/python-dev/2003-October/039214.html</a></aside>
<aside class="footnote brackets" id="id48" role="doc-footnote">
<dt class="label" id="id48">[4]<em> (<a href='#id5'>1</a>, <a href='#id6'>2</a>) </em></dt>
<dd>Better Control of Nested Lexical Scopes (Almann T. Goo)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061568.html">https://mail.python.org/pipermail/python-dev/2006-February/061568.html</a></aside>
<aside class="footnote brackets" id="id49" role="doc-footnote">
<dt class="label" id="id49">[<a href="#id18">5</a>]</dt>
<dd>PEP for Better Control of Nested Lexical Scopes (Jeremy Hylton)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061602.html">https://mail.python.org/pipermail/python-dev/2006-February/061602.html</a></aside>
<aside class="footnote brackets" id="id50" role="doc-footnote">
<dt class="label" id="id50">[<a href="#id19">6</a>]</dt>
<dd>PEP for Better Control of Nested Lexical Scopes (Almann T. Goo)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061603.html">https://mail.python.org/pipermail/python-dev/2006-February/061603.html</a></aside>
<aside class="footnote brackets" id="id51" role="doc-footnote">
<dt class="label" id="id51">[<a href="#id10">7</a>]</dt>
<dd>Using and binding relative names (Phillip J. Eby)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061636.html">https://mail.python.org/pipermail/python-dev/2006-February/061636.html</a></aside>
<aside class="footnote brackets" id="id52" role="doc-footnote">
<dt class="label" id="id52">[<a href="#id12">8</a>]</dt>
<dd>Using and binding relative names (Steven Bethard)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061749.html">https://mail.python.org/pipermail/python-dev/2006-February/061749.html</a></aside>
<aside class="footnote brackets" id="id53" role="doc-footnote">
<dt class="label" id="id53">[9]<em> (<a href='#id7'>1</a>, <a href='#id20'>2</a>) </em></dt>
<dd>Lexical scoping in Python 3k (Ka-Ping Yee)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066862.html">https://mail.python.org/pipermail/python-dev/2006-July/066862.html</a></aside>
<aside class="footnote brackets" id="id54" role="doc-footnote">
<dt class="label" id="id54">[<a href="#id21">10</a>]</dt>
<dd>Lexical scoping in Python 3k (Greg Ewing)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066889.html">https://mail.python.org/pipermail/python-dev/2006-July/066889.html</a></aside>
<aside class="footnote brackets" id="id55" role="doc-footnote">
<dt class="label" id="id55">[<a href="#id22">11</a>]</dt>
<dd>Lexical scoping in Python 3k (Ka-Ping Yee)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066942.html">https://mail.python.org/pipermail/python-dev/2006-July/066942.html</a></aside>
<aside class="footnote brackets" id="id56" role="doc-footnote">
<dt class="label" id="id56">[<a href="#id3">12</a>]</dt>
<dd>Lexical scoping in Python 3k (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066950.html">https://mail.python.org/pipermail/python-dev/2006-July/066950.html</a></aside>
<aside class="footnote brackets" id="id57" role="doc-footnote">
<dt class="label" id="id57">[<a href="#id8">13</a>]</dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Talin)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066978.html">https://mail.python.org/pipermail/python-dev/2006-July/066978.html</a></aside>
<aside class="footnote brackets" id="id58" role="doc-footnote">
<dt class="label" id="id58">[<a href="#id37">14</a>]</dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066991.html">https://mail.python.org/pipermail/python-dev/2006-July/066991.html</a></aside>
</aside>
<p>[15] Explicit Lexical Scoping (pre-PEP?) (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066995.html">https://mail.python.org/pipermail/python-dev/2006-July/066995.html</a></p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id59" role="doc-footnote">
<dt class="label" id="id59">[<a href="#id39">16</a>]</dt>
<dd>Lexical scoping in Python 3k (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/066968.html">https://mail.python.org/pipermail/python-dev/2006-July/066968.html</a></aside>
<aside class="footnote brackets" id="id60" role="doc-footnote">
<dt class="label" id="id60">[<a href="#id13">17</a>]</dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/067004.html">https://mail.python.org/pipermail/python-dev/2006-July/067004.html</a></aside>
<aside class="footnote brackets" id="id61" role="doc-footnote">
<dt class="label" id="id61">[18]<em> (<a href='#id23'>1</a>, <a href='#id24'>2</a>, <a href='#id25'>3</a>) </em></dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Andrew Clover)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/067007.html">https://mail.python.org/pipermail/python-dev/2006-July/067007.html</a></aside>
<aside class="footnote brackets" id="id62" role="doc-footnote">
<dt class="label" id="id62">[19]<em> (<a href='#id38'>1</a>, <a href='#id43'>2</a>) </em></dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/067067.html">https://mail.python.org/pipermail/python-dev/2006-July/067067.html</a></aside>
<aside class="footnote brackets" id="id63" role="doc-footnote">
<dt class="label" id="id63">[<a href="#id26">20</a>]</dt>
<dd>Explicit Lexical Scoping (pre-PEP?) (Matthew Barnes)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-July/067221.html">https://mail.python.org/pipermail/python-dev/2006-July/067221.html</a></aside>
<aside class="footnote brackets" id="id64" role="doc-footnote">
<dt class="label" id="id64">[<a href="#id9">21</a>]</dt>
<dd>Sky pie: a “var” keyword (a thread started by Neil Toronto)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-October/003968.html">https://mail.python.org/pipermail/python-3000/2006-October/003968.html</a></aside>
<aside class="footnote brackets" id="id65" role="doc-footnote">
<dt class="label" id="id65">[22]<em> (<a href='#id27'>1</a>, <a href='#id28'>2</a>, <a href='#id29'>3</a>, <a href='#id30'>4</a>, <a href='#id31'>5</a>, <a href='#id32'>6</a>, <a href='#id33'>7</a>) </em></dt>
<dd>Alternatives to outer (Talin)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-October/004021.html">https://mail.python.org/pipermail/python-3000/2006-October/004021.html</a></aside>
<aside class="footnote brackets" id="id66" role="doc-footnote">
<dt class="label" id="id66">[<a href="#id34">23</a>]</dt>
<dd>Alternatives to outer (Jim Jewett)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-November/004153.html">https://mail.python.org/pipermail/python-3000/2006-November/004153.html</a></aside>
<aside class="footnote brackets" id="id67" role="doc-footnote">
<dt class="label" id="id67">[<a href="#id40">24</a>]</dt>
<dd>Draft PEP for outer scopes (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-November/004166.html">https://mail.python.org/pipermail/python-3000/2006-November/004166.html</a></aside>
<aside class="footnote brackets" id="id68" role="doc-footnote">
<dt class="label" id="id68">[<a href="#id35">25</a>]</dt>
<dd>Draft PEP for outer scopes (Talin)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-November/004190.html">https://mail.python.org/pipermail/python-3000/2006-November/004190.html</a></aside>
<aside class="footnote brackets" id="id69" role="doc-footnote">
<dt class="label" id="id69">[<a href="#id44">26</a>]</dt>
<dd>Draft PEP for outer scopes (Alyssa Coghlan)
<a class="reference external" href="https://mail.python.org/pipermail/python-3000/2006-November/004237.html">https://mail.python.org/pipermail/python-3000/2006-November/004237.html</a></aside>
<aside class="footnote brackets" id="id70" role="doc-footnote">
<dt class="label" id="id70">[<a href="#id36">27</a>]</dt>
<dd>Global variable (version 2006-11-01T01:23:16)
<a class="reference external" href="https://en.wikipedia.org/w/index.php?title=Global_variable&amp;oldid=85001451">https://en.wikipedia.org/w/index.php?title=Global_variable&amp;oldid=85001451</a></aside>
<aside class="footnote brackets" id="id71" role="doc-footnote">
<dt class="label" id="id71">[<a href="#id4">28</a>]</dt>
<dd>Ruby 2.0 block local variable
<a class="reference external" href="https://web.archive.org/web/20070105131417/http://redhanded.hobix.com/inspect/ruby20BlockLocalVariable.html">https://web.archive.org/web/20070105131417/http://redhanded.hobix.com/inspect/ruby20BlockLocalVariable.html</a></aside>
<aside class="footnote brackets" id="id72" role="doc-footnote">
<dt class="label" id="id72">[<a href="#id41">29</a>]</dt>
<dd>Issue 4199: combining assignment with global &amp; nonlocal (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2013-June/127142.html">https://mail.python.org/pipermail/python-dev/2013-June/127142.html</a></aside>
<aside class="footnote brackets" id="id73" role="doc-footnote">
<dt class="label" id="id73">[<a href="#id42">30</a>]</dt>
<dd>Whatever happened to nonlocal x = y? (Guido van Rossum)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2018-January/151627.html">https://mail.python.org/pipermail/python-dev/2018-January/151627.html</a></aside>
<aside class="footnote brackets" id="id74" role="doc-footnote">
<dt class="label" id="id74">[<a href="#id11">31</a>]</dt>
<dd>Using and binding relative names (Almann T. Goo)
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2006-February/061761.html">https://mail.python.org/pipermail/python-dev/2006-February/061761.html</a></aside>
</aside>
</section>
<section id="acknowledgements">
<h2><a class="toc-backref" href="#acknowledgements" role="doc-backlink">Acknowledgements</a></h2>
<p>The ideas and proposals mentioned in this PEP are gleaned from
countless Python-Dev postings. Thanks to Jim Jewett, Mike Orr,
Jason Orendorff, and Christian Tanzer for suggesting specific
edits to this PEP.</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-3104.rst">https://github.com/python/peps/blob/main/peps/pep-3104.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-3104.rst">2023-10-11 12:05:51 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#other-languages">Other Languages</a><ul>
<li><a class="reference internal" href="#javascript-perl-scheme-smalltalk-gnu-c-c-2-0">JavaScript, Perl, Scheme, Smalltalk, GNU C, C# 2.0</a></li>
<li><a class="reference internal" href="#ruby-as-of-1-8">Ruby (as of 1.8)</a></li>
</ul>
</li>
<li><a class="reference internal" href="#overview-of-proposals">Overview of Proposals</a><ul>
<li><a class="reference internal" href="#new-syntax-in-the-binding-outer-scope">New Syntax in the Binding (Outer) Scope</a><ul>
<li><a class="reference internal" href="#scope-override-declaration">Scope Override Declaration</a></li>
<li><a class="reference internal" href="#required-variable-declaration">Required Variable Declaration</a></li>
</ul>
</li>
<li><a class="reference internal" href="#new-syntax-in-the-referring-inner-scope">New Syntax in the Referring (Inner) Scope</a><ul>
<li><a class="reference internal" href="#outer-reference-expression">Outer Reference Expression</a></li>
<li><a class="reference internal" href="#rebinding-operator">Rebinding Operator</a></li>
<li><a class="reference internal" href="#id15">Scope Override Declaration</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#proposed-solution">Proposed Solution</a></li>
<li><a class="reference internal" href="#backward-compatibility">Backward Compatibility</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#acknowledgements">Acknowledgements</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-3104.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>