CINXE.COM
PEP 640 – Unused variable syntax | peps.python.org
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="color-scheme" content="light dark"> <title>PEP 640 – Unused variable syntax | peps.python.org</title> <link rel="shortcut icon" href="../_static/py.png"> <link rel="canonical" href="https://peps.python.org/pep-0640/"> <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 640 – Unused variable syntax | peps.python.org'> <meta property="og:description" content="This PEP proposes new syntax for unused variables, providing a pseudo-name that can be assigned to but not otherwise used. The assignment doesn’t actually happen, and the value is discarded instead."> <meta property="og:type" content="website"> <meta property="og:url" content="https://peps.python.org/pep-0640/"> <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 proposes new syntax for unused variables, providing a pseudo-name that can be assigned to but not otherwise used. The assignment doesn’t actually happen, and the value is discarded instead."> <meta name="theme-color" content="#3776ab"> </head> <body> <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <symbol id="svg-sun-half" viewBox="0 0 24 24" pointer-events="all"> <title>Following system colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="9"></circle> <path d="M12 3v18m0-12l4.65-4.65M12 14.3l7.37-7.37M12 19.6l8.85-8.85"></path> </svg> </symbol> <symbol id="svg-moon" viewBox="0 0 24 24" pointer-events="all"> <title>Selected dark colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path stroke="none" d="M0 0h24v24H0z" fill="none"></path> <path d="M12 3c.132 0 .263 0 .393 0a7.5 7.5 0 0 0 7.92 12.446a9 9 0 1 1 -8.313 -12.454z"></path> </svg> </symbol> <symbol id="svg-sun" viewBox="0 0 24 24" pointer-events="all"> <title>Selected light colour scheme</title> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="5"></circle> <line x1="12" y1="1" x2="12" y2="3"></line> <line x1="12" y1="21" x2="12" y2="23"></line> <line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line> <line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line> <line x1="1" y1="12" x2="3" y2="12"></line> <line x1="21" y1="12" x2="23" y2="12"></line> <line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line> <line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line> </svg> </symbol> </svg> <script> document.documentElement.dataset.colour_scheme = localStorage.getItem("colour_scheme") || "auto" </script> <section id="pep-page-section"> <header> <h1>Python Enhancement Proposals</h1> <ul class="breadcrumbs"> <li><a href="https://www.python.org/" title="The Python Programming Language">Python</a> » </li> <li><a href="../pep-0000/">PEP Index</a> » </li> <li>PEP 640</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 640 – Unused variable syntax</h1> <dl class="rfc2822 field-list simple"> <dt class="field-odd">Author<span class="colon">:</span></dt> <dd class="field-odd">Thomas Wouters <thomas at python.org></dd> <dt class="field-even">Status<span class="colon">:</span></dt> <dd class="field-even"><abbr title="Formally declined and will not be accepted">Rejected</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">04-Oct-2020</dd> <dt class="field-odd">Python-Version<span class="colon">:</span></dt> <dd class="field-odd">3.10</dd> <dt class="field-even">Post-History<span class="colon">:</span></dt> <dd class="field-even">19-Oct-2020</dd> <dt class="field-odd">Resolution<span class="colon">:</span></dt> <dd class="field-odd"><a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/">Python-Dev message</a></dd> </dl> <hr class="docutils" /> <section id="contents"> <details><summary>Table of Contents</summary><ul class="simple"> <li><a class="reference internal" href="#rejection-note">Rejection Note</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a></li> <li><a class="reference internal" href="#open-issues">Open Issues</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> </details></section> <section id="rejection-note"> <h2><a class="toc-backref" href="#rejection-note" role="doc-backlink">Rejection Note</a></h2> <p>Rejected by the Steering Council: <a class="reference external" href="https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/">https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/</a></p> </section> <section id="abstract"> <h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2> <p>This PEP proposes new syntax for <em>unused variables</em>, providing a pseudo-name that can be assigned to but not otherwise used. The assignment doesn’t actually happen, and the value is discarded instead.</p> </section> <section id="motivation"> <h2><a class="toc-backref" href="#motivation" role="doc-backlink">Motivation</a></h2> <p>In Python it is somewhat common to need to do an assignment without actually needing the result. Conventionally, people use either <code class="docutils literal notranslate"><span class="pre">"_"</span></code> or a name such as <code class="docutils literal notranslate"><span class="pre">"unused"</span></code> (or with <code class="docutils literal notranslate"><span class="pre">"unused"</span></code> as a prefix) for this. It’s most common in <em>unpacking assignments</em>:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">x</span><span class="p">,</span> <span class="n">unused</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">x</span><span class="p">,</span> <span class="o">*</span><span class="n">unused</span><span class="p">,</span> <span class="n">z</span> <span class="o">=</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> </pre></div> </div> <p>It’s also used in <code class="docutils literal notranslate"><span class="pre">for</span></code> loops and comprehensions:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">for</span> <span class="n">unused</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span> <span class="o">...</span> <span class="p">[</span> <span class="n">SpamObject</span><span class="p">()</span> <span class="k">for</span> <span class="n">unused</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="p">]</span> </pre></div> </div> <p>The use of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> in these cases is probably the most common, but it potentially conflicts with the use of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> in internationalization, where a call like gettext.gettext() is bound to <code class="docutils literal notranslate"><span class="pre">"_"</span></code> and used to mark strings for translation.</p> <p>In the proposal to add Pattern Matching to Python (originally <a class="pep reference internal" href="../pep-0622/" title="PEP 622 – Structural Pattern Matching">PEP 622</a>, now split into <a class="pep reference internal" href="../pep-0634/" title="PEP 634 – Structural Pattern Matching: Specification">PEP 634</a>, <a class="pep reference internal" href="../pep-0635/" title="PEP 635 – Structural Pattern Matching: Motivation and Rationale">PEP 635</a> and <a class="pep reference internal" href="../pep-0636/" title="PEP 636 – Structural Pattern Matching: Tutorial">PEP 636</a>), <code class="docutils literal notranslate"><span class="pre">"_"</span></code> has an <em>additional</em> special meaning. It is a wildcard pattern, used in places where variables could be assigned to, to indicate anything should be matched but not assigned to anything. The choice of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> there matches the use of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> in other languages, but the semantic difference with <code class="docutils literal notranslate"><span class="pre">"_"</span></code> elsewhere in Python is significant.</p> <p>This PEP proposes to allow a special token, <code class="docutils literal notranslate"><span class="pre">"?"</span></code>, to be used instead of any valid name in assignment. This has most of the benefits of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> without affecting other uses of that otherwise regular variable. Allowing the use of the same wildcard pattern would make pattern matching and unpacking assignment more consistent with each other.</p> </section> <section id="rationale"> <h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2> <p>Marking certain variables as unused is a useful tool, as it helps clarity of purpose of the code. It makes it obvious to readers of the code as well as automated linters, that a particular variable is <em>intentionally</em> unused.</p> <p>However, despite the convention, <code class="docutils literal notranslate"><span class="pre">"_"</span></code> is not a special variable. The value is still assigned to, the object it refers to is still kept alive until the end of the scope, and it can still be used. Nor is the use of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> for unused variables entirely ubiquitous, since it conflicts with conventional internationalization, it isn’t obvious that it is a regular variable, and it isn’t as obviously unused like a variable named <code class="docutils literal notranslate"><span class="pre">"unused"</span></code>.</p> <p>In the Pattern Matching proposal, the use of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> for wildcard patterns side-steps the problems of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> for unused variables by virtue of it being in a separate scope. The only conflict it has with internationalization is one of potential confusion, it will not actually interact with uses of a global variable called <code class="docutils literal notranslate"><span class="pre">"_"</span></code>. However, the special-casing of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> for this wildcard pattern purpose is still problematic: the different semantics <em>and meaning</em> of <code class="docutils literal notranslate"><span class="pre">"_"</span></code> inside pattern matching and outside of it means a break in consistency in Python.</p> <p>Introducing <code class="docutils literal notranslate"><span class="pre">"?"</span></code> as special syntax for unused variables <em>both inside and outside pattern matching</em> allows us to retain that consistency. It avoids the conflict with internationalization <em>or any other uses of _ as a variable</em>. It makes unpacking assignment align more closely with pattern matching, making it easier to explain pattern matching as an extension of unpacking assignment.</p> <p>In terms of code readability, using a special token makes it easier to find out what it means (<code class="docutils literal notranslate"><span class="pre">"what</span> <span class="pre">does</span> <span class="pre">question</span> <span class="pre">mark</span> <span class="pre">in</span> <span class="pre">Python</span> <span class="pre">do"</span></code> versus <code class="docutils literal notranslate"><span class="pre">"why</span> <span class="pre">is</span> <span class="pre">my</span> <span class="pre">_</span> <span class="pre">variable</span> <span class="pre">not</span> <span class="pre">getting</span> <span class="pre">assigned</span> <span class="pre">to"</span></code>), and makes it more obvious that the actual intent is for the value to be unused – since it is entirely impossible to use it.</p> </section> <section id="specification"> <h2><a class="toc-backref" href="#specification" role="doc-backlink">Specification</a></h2> <p>A new token is introduced, <code class="docutils literal notranslate"><span class="pre">"?"</span></code>, or <code class="docutils literal notranslate"><span class="pre">token.QMARK</span></code>.</p> <p>The grammar is modified to allow <code class="docutils literal notranslate"><span class="pre">"?"</span></code> in assignment contexts (<code class="docutils literal notranslate"><span class="pre">star_atom</span></code> and <code class="docutils literal notranslate"><span class="pre">t_atom</span></code> in the current grammar), creating a <code class="docutils literal notranslate"><span class="pre">Name</span></code> AST node with identifier set to NULL.</p> <p>The AST is modified to allow the <code class="docutils literal notranslate"><span class="pre">Name</span></code> expression’s identifier to be optional (it is currently required). The identifier being empty would only be allowed in a <code class="docutils literal notranslate"><span class="pre">STORE</span></code> context.</p> <p>In CPython, the bytecode compiler is modified to emit <code class="docutils literal notranslate"><span class="pre">POP_TOP</span></code> instead of <code class="docutils literal notranslate"><span class="pre">STORE_NAME</span></code> for <code class="docutils literal notranslate"><span class="pre">Name</span></code> nodes with no identifier. Other uses of the <code class="docutils literal notranslate"><span class="pre">Name</span></code> node are updated to handle the identifier being empty, as appropriate.</p> <p>The uses of the modified grammar nodes encompass at least the following forms of assignment:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span>? = ... x, ?, z = ... x, *?, z = ... for ? in range(3): ... # including comprehension forms for x, ?, z in matrix: ... # including comprehension forms with open(f) as ?: ... with func() as (x, ?, z): ... </pre></div> </div> <p>The use of a single <code class="docutils literal notranslate"><span class="pre">"?"</span></code>, not in an unpacking context, is allowed in normal assignment and the <code class="docutils literal notranslate"><span class="pre">with</span></code> statement. It doesn’t really make sense on its own, and it is possible to disallow those specific cases. However, <code class="docutils literal notranslate"><span class="pre">for</span> <span class="pre">?</span> <span class="pre">in</span> <span class="pre">range(3)</span></code> clearly has its uses, so for consistency reasons if nothing else it seems more sensible to allow the use of the single <code class="docutils literal notranslate"><span class="pre">"?"</span></code> in other cases.</p> <p>Using <code class="docutils literal notranslate"><span class="pre">"?"</span></code> in augmented assignment (<code class="docutils literal notranslate"><span class="pre">?</span> <span class="pre">*=</span> <span class="pre">2</span></code>) is not allowed, since <code class="docutils literal notranslate"><span class="pre">"?"</span></code> can only be used for assignment. Having multiple occurrences of <code class="docutils literal notranslate"><span class="pre">"?"</span></code> is valid, just like when assigning to names, and the assignments do not interfere with each other.</p> </section> <section id="backwards-compatibility"> <h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2> <p>Introducing a new token means there are no backward compatibility concerns. No valid syntax changes meaning.</p> <p><code class="docutils literal notranslate"><span class="pre">"?"</span></code> is not considered an identifier, so <code class="docutils literal notranslate"><span class="pre">str.isidentifier()</span></code> does not change.</p> <p>The AST does change in an incompatible way, as the identifier of a Name token can now be empty. Code using the AST will have to be adjusted accordingly.</p> </section> <section id="how-to-teach-this"> <h2><a class="toc-backref" href="#how-to-teach-this" role="doc-backlink">How to Teach This</a></h2> <p><code class="docutils literal notranslate"><span class="pre">"?"</span></code> can be introduced along with unpacking assignment, explaining it is special syntax for ‘unused’ and mentioning that it can also be used in other places. Alternatively, it could be introduced as part of an explanation on assignment in <code class="docutils literal notranslate"><span class="pre">for</span></code> loops, showing an example where the loop variable is unused.</p> <p><a class="pep reference internal" href="../pep-0636/" title="PEP 636 – Structural Pattern Matching: Tutorial">PEP 636</a> discusses how to teach <code class="docutils literal notranslate"><span class="pre">"_"</span></code>, and can simply replace <code class="docutils literal notranslate"><span class="pre">"_"</span></code> with <code class="docutils literal notranslate"><span class="pre">"?"</span></code>, perhaps noting that <code class="docutils literal notranslate"><span class="pre">"?"</span></code> is similarly usable in other contexts.</p> </section> <section id="reference-implementation"> <h2><a class="toc-backref" href="#reference-implementation" role="doc-backlink">Reference Implementation</a></h2> <p>A prototype implementation exists at <<a class="reference external" href="https://github.com/Yhg1s/cpython/tree/nonassign">https://github.com/Yhg1s/cpython/tree/nonassign</a>>.</p> </section> <section id="rejected-ideas"> <h2><a class="toc-backref" href="#rejected-ideas" role="doc-backlink">Rejected Ideas</a></h2> </section> <section id="open-issues"> <h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2> <p>Should <code class="docutils literal notranslate"><span class="pre">"?"</span></code> be allowed in the following contexts:</p> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span># imports done for side-effect only. import os as ? from os import path as ? # Function defined for side-effects only (e.g. decorators) @register_my_func def ?(...): ... # Class defined for side-effects only (e.g. decorators, __init_subclass__) class ?(...): ... # Parameters defined for unused positional-only arguments: def f(a, ?, ?): ... lambda a, ?, ?: ... # Unused variables with type annotations: ?: int = f() # Exception handling: try: ... except Exception as ?: ... # With blocks: with open(f) as ?: ... </pre></div> </div> <p>Some of these may seem to make sense from a consistency point of view, but practical uses are limited and dubious. Type annotations on <code class="docutils literal notranslate"><span class="pre">"?"</span></code> and using it with <code class="docutils literal notranslate"><span class="pre">except</span></code> and <code class="docutils literal notranslate"><span class="pre">with</span></code> do not seem to make any sense. In the reference implementation, <code class="docutils literal notranslate"><span class="pre">except</span></code> is not supported (the existing syntax only allows a name) but <code class="docutils literal notranslate"><span class="pre">with</span></code> is (by virtue of the existing syntax supporting unpacking assignment).</p> <p>Should this PEP be accepted even if pattern matching is rejected?</p> </section> <section id="copyright"> <h2><a class="toc-backref" href="#copyright" role="doc-backlink">Copyright</a></h2> <p>This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.</p> </section> </section> <hr class="docutils" /> <p>Source: <a class="reference external" href="https://github.com/python/peps/blob/main/peps/pep-0640.rst">https://github.com/python/peps/blob/main/peps/pep-0640.rst</a></p> <p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0640.rst">2025-02-01 08:55:40 GMT</a></p> </article> <nav id="pep-sidebar"> <h2>Contents</h2> <ul> <li><a class="reference internal" href="#rejection-note">Rejection Note</a></li> <li><a class="reference internal" href="#abstract">Abstract</a></li> <li><a class="reference internal" href="#motivation">Motivation</a></li> <li><a class="reference internal" href="#rationale">Rationale</a></li> <li><a class="reference internal" href="#specification">Specification</a></li> <li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li> <li><a class="reference internal" href="#how-to-teach-this">How to Teach This</a></li> <li><a class="reference internal" href="#reference-implementation">Reference Implementation</a></li> <li><a class="reference internal" href="#rejected-ideas">Rejected Ideas</a></li> <li><a class="reference internal" href="#open-issues">Open Issues</a></li> <li><a class="reference internal" href="#copyright">Copyright</a></li> </ul> <br> <a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0640.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>