python-peps/pep-0310/index.html

362 lines
24 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 310 Reliable Acquisition/Release Pairs | peps.python.org</title>
<link rel="shortcut icon" href="../_static/py.png">
<link rel="canonical" href="https://peps.python.org/pep-0310/">
<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 310 Reliable Acquisition/Release Pairs | peps.python.org'>
<meta property="og:description" content="It would be nice to have a less typing-intense way of writing:">
<meta property="og:type" content="website">
<meta property="og:url" content="https://peps.python.org/pep-0310/">
<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="It would be nice to have a less typing-intense way of writing:">
<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 310</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 310 Reliable Acquisition/Release Pairs</h1>
<dl class="rfc2822 field-list simple">
<dt class="field-odd">Author<span class="colon">:</span></dt>
<dd class="field-odd">Michael Hudson &lt;mwh&#32;&#97;t&#32;python.net&gt;,
Paul Moore &lt;p.f.moore&#32;&#97;t&#32;gmail.com&gt;</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">18-Dec-2002</dd>
<dt class="field-odd">Python-Version<span class="colon">:</span></dt>
<dd class="field-odd">2.4</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="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#basic-syntax-and-semantics">Basic Syntax and Semantics</a></li>
<li><a class="reference internal" href="#possible-extensions">Possible Extensions</a><ul>
<li><a class="reference internal" href="#multiple-expressions">Multiple expressions</a></li>
<li><a class="reference internal" href="#exception-handling">Exception handling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#implementation-notes">Implementation Notes</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#alternative-ideas">Alternative Ideas</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#cost-of-adoption">Cost of Adoption</a></li>
<li><a class="reference internal" href="#cost-of-non-adoption">Cost of Non-Adoption</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
</details></section>
<section id="abstract">
<h2><a class="toc-backref" href="#abstract" role="doc-backlink">Abstract</a></h2>
<p>It would be nice to have a less typing-intense way of writing:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">the_lock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="o">....</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">the_lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</pre></div>
</div>
<p>This PEP proposes a piece of syntax (a with block) and a
“small-i” interface that generalizes the above.</p>
</section>
<section id="pronouncement">
<h2><a class="toc-backref" href="#pronouncement" role="doc-backlink">Pronouncement</a></h2>
<p>This PEP is rejected in favor of <a class="pep reference internal" href="../pep-0343/" title="PEP 343 The “with” Statement">PEP 343</a>.</p>
</section>
<section id="rationale">
<h2><a class="toc-backref" href="#rationale" role="doc-backlink">Rationale</a></h2>
<p>One of the advantages of Pythons exception handling philosophy is
that it makes it harder to do the “wrong” thing (e.g. failing to
check the return value of some system call). Currently, this does
not apply to resource cleanup. The current syntax for acquisition
and release of a resource (for example, a lock) is:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">the_lock</span><span class="o">.</span><span class="n">acquire</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="o">....</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">the_lock</span><span class="o">.</span><span class="n">release</span><span class="p">()</span>
</pre></div>
</div>
<p>This syntax separates the acquisition and release by a (possibly
large) block of code, which makes it difficult to confirm “at a
glance” that the code manages the resource correctly. Another
common error is to code the “acquire” call within the try block,
which incorrectly releases the lock if the acquire fails.</p>
</section>
<section id="basic-syntax-and-semantics">
<h2><a class="toc-backref" href="#basic-syntax-and-semantics" role="doc-backlink">Basic Syntax and Semantics</a></h2>
<p>The syntax of a with statement is as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;with&#39;</span> <span class="p">[</span> <span class="n">var</span> <span class="s1">&#39;=&#39;</span> <span class="p">]</span> <span class="n">expr</span> <span class="s1">&#39;:&#39;</span>
<span class="n">suite</span>
</pre></div>
</div>
<p>This statement is defined as being equivalent to the following
sequence of statements:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">var</span> <span class="o">=</span> <span class="n">expr</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="s2">&quot;__enter__&quot;</span><span class="p">):</span>
<span class="n">var</span><span class="o">.</span><span class="fm">__enter__</span><span class="p">()</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">suite</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">var</span><span class="o">.</span><span class="fm">__exit__</span><span class="p">()</span>
</pre></div>
</div>
<p>(The presence of an <code class="docutils literal notranslate"><span class="pre">__exit__</span></code> method is <em>not</em> checked like that of
<code class="docutils literal notranslate"><span class="pre">__enter__</span></code> to ensure that using inappropriate objects in with:
statements gives an error).</p>
<p>If the variable is omitted, an unnamed object is allocated on the
stack. In that case, the suite has no access to the unnamed object.</p>
</section>
<section id="possible-extensions">
<h2><a class="toc-backref" href="#possible-extensions" role="doc-backlink">Possible Extensions</a></h2>
<p>A number of potential extensions to the basic syntax have been
discussed on the Python Developers list. None of these extensions
are included in the solution proposed by this PEP. In many cases,
the arguments are nearly equally strong in both directions. In
such cases, the PEP has always chosen simplicity, simply because
where extra power is needed, the existing try block is available.</p>
<section id="multiple-expressions">
<h3><a class="toc-backref" href="#multiple-expressions" role="doc-backlink">Multiple expressions</a></h3>
<p>One proposal was for allowing multiple expressions within one
with statement. The <code class="docutils literal notranslate"><span class="pre">__enter__</span></code> methods would be called left to
right, and the <code class="docutils literal notranslate"><span class="pre">__exit__</span></code> methods right to left. The advantage of
doing so is that where more than one resource is being managed,
nested with statements will result in code drifting towards the
right margin. The solution to this problem is the same as for any
other deep nesting - factor out some of the code into a separate
function. Furthermore, the question of what happens if one of the
<code class="docutils literal notranslate"><span class="pre">__exit__</span></code> methods raises an exception (should the other <code class="docutils literal notranslate"><span class="pre">__exit__</span></code>
methods be called?) needs to be addressed.</p>
</section>
<section id="exception-handling">
<h3><a class="toc-backref" href="#exception-handling" role="doc-backlink">Exception handling</a></h3>
<p>An extension to the protocol to include an optional <code class="docutils literal notranslate"><span class="pre">__except__</span></code>
handler, which is called when an exception is raised, and which
can handle or re-raise the exception, has been suggested. It is
not at all clear that the semantics of this extension can be made
precise and understandable. For example, should the equivalent
code be <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span> <span class="pre">...</span> <span class="pre">else</span></code> if an exception handler is
defined, and <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">finally</span></code> if not? How can this be determined
at compile time, in general? The alternative is to define the
code as expanding to a <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span></code> inside a <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">finally</span></code>.
But this may not do the right thing in real life.</p>
<p>The only use case identified for exception handling is with
transactional processing (commit on a clean finish, and rollback
on an exception). This is probably just as easy to handle with a
conventional <code class="docutils literal notranslate"><span class="pre">try</span> <span class="pre">...</span> <span class="pre">except</span> <span class="pre">...</span> <span class="pre">else</span></code> block, and so the PEP does
not include any support for exception handlers.</p>
</section>
</section>
<section id="implementation-notes">
<h2><a class="toc-backref" href="#implementation-notes" role="doc-backlink">Implementation Notes</a></h2>
<p>There is a potential race condition in the code specified as
equivalent to the with statement. For example, if a
<code class="docutils literal notranslate"><span class="pre">KeyboardInterrupt</span></code> exception is raised between the completion of
the <code class="docutils literal notranslate"><span class="pre">__enter__</span></code> method call and the start of the try block, the
<code class="docutils literal notranslate"><span class="pre">__exit__</span></code> method will not be called. This can lead to resource
leaks, or to deadlocks. [XXX Guido has stated that he cares about
this sort of race condition, and intends to write some C magic to
handle them. The implementation of the with statement should
copy this.]</p>
</section>
<section id="open-issues">
<h2><a class="toc-backref" href="#open-issues" role="doc-backlink">Open Issues</a></h2>
<p>Should existing classes (for example, file-like objects and locks)
gain appropriate <code class="docutils literal notranslate"><span class="pre">__enter__</span></code> and <code class="docutils literal notranslate"><span class="pre">__exit__</span></code> methods? The obvious
reason in favour is convenience (no adapter needed). The argument
against is that if built-in files have this but (say) <code class="docutils literal notranslate"><span class="pre">StringIO</span></code>
does not, then code that uses “with” on a file object cant be
reused with a <code class="docutils literal notranslate"><span class="pre">StringIO</span></code> object. So <code class="docutils literal notranslate"><span class="pre">__exit__</span> <span class="pre">=</span> <span class="pre">close</span></code> becomes a part
of the “file-like object” protocol, which user-defined classes may
need to support.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">__enter__</span></code> hook may be unnecessary - for many use cases, an
adapter class is needed and in that case, the work done by the
<code class="docutils literal notranslate"><span class="pre">__enter__</span></code> hook can just as easily be done in the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> hook.</p>
<p>If a way of controlling object lifetimes explicitly was available,
the function of the <code class="docutils literal notranslate"><span class="pre">__exit__</span></code> hook could be taken over by the
existing <code class="docutils literal notranslate"><span class="pre">__del__</span></code> hook. An email exchange <a class="footnote-reference brackets" href="#id4" id="id1">[1]</a> with a proponent of
this approach left one of the authors even more convinced that
it isnt the right idea…</p>
<p>It has been suggested <a class="footnote-reference brackets" href="#id5" id="id2">[2]</a> that the “__exit__” method be called
“close”, or that a “close” method should be considered if no
<code class="docutils literal notranslate"><span class="pre">__exit__</span></code> method is found, to increase the “out-of-the-box utility”
of the “with …” construct.</p>
<p>There are some similarities in concept between with …’ blocks
and generators, which have led to proposals that for loops could
implement the with block functionality <a class="footnote-reference brackets" href="#id6" id="id3">[3]</a>. While neat on some
levels, we think that for loops should stick to being loops.</p>
</section>
<section id="alternative-ideas">
<h2><a class="toc-backref" href="#alternative-ideas" role="doc-backlink">Alternative Ideas</a></h2>
<p>IEXEC: Holger Krekel generalised approach with XML-like syntax
(no URL found…).</p>
<p>Holger has much more far-reaching ideas about “execution monitors”
that are informed about details of control flow in the monitored
block. While interesting, these ideas could change the language
in deep and subtle ways and as such belong to a different PEP.</p>
<p>Any Smalltalk/Ruby anonymous block style extension obviously
subsumes this one.</p>
<p><a class="pep reference internal" href="../pep-0319/" title="PEP 319 Python Synchronize/Asynchronize Block">PEP 319</a> is in the same area, but did not win support when aired on
python-dev.</p>
</section>
<section id="backwards-compatibility">
<h2><a class="toc-backref" href="#backwards-compatibility" role="doc-backlink">Backwards Compatibility</a></h2>
<p>This PEP proposes a new keyword, so the <code class="docutils literal notranslate"><span class="pre">__future__</span></code> game will need
to be played.</p>
</section>
<section id="cost-of-adoption">
<h2><a class="toc-backref" href="#cost-of-adoption" role="doc-backlink">Cost of Adoption</a></h2>
<p>Those who claim the language is getting larger and more
complicated have something else to complain about. Its something
else to teach.</p>
<p>For the proposal to be useful, many file-like and lock-like
classes in the standard library and other code will have to have</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="fm">__exit__</span> <span class="o">=</span> <span class="n">close</span>
</pre></div>
</div>
<p>or similar added.</p>
</section>
<section id="cost-of-non-adoption">
<h2><a class="toc-backref" href="#cost-of-non-adoption" role="doc-backlink">Cost of Non-Adoption</a></h2>
<p>Writing correct code continues to be more effort than writing
incorrect code.</p>
</section>
<section id="references">
<h2><a class="toc-backref" href="#references" role="doc-backlink">References</a></h2>
<p>There are various python-list and python-dev discussions that
could be mentioned here.</p>
<aside class="footnote-list brackets">
<aside class="footnote brackets" id="id4" role="doc-footnote">
<dt class="label" id="id4">[<a href="#id1">1</a>]</dt>
<dd>Off-list conversation between Michael Hudson and Bill Soudan
(made public with permission)
<a class="reference external" href="http://starship.python.net/crew/mwh/pep310/">http://starship.python.net/crew/mwh/pep310/</a></aside>
<aside class="footnote brackets" id="id5" role="doc-footnote">
<dt class="label" id="id5">[<a href="#id2">2</a>]</dt>
<dd>Samuele Pedroni on python-dev
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2003-August/037795.html">https://mail.python.org/pipermail/python-dev/2003-August/037795.html</a></aside>
<aside class="footnote brackets" id="id6" role="doc-footnote">
<dt class="label" id="id6">[<a href="#id3">3</a>]</dt>
<dd>Thread on python-dev with subject
<code class="docutils literal notranslate"><span class="pre">[Python-Dev]</span> <span class="pre">pre-PEP:</span> <span class="pre">Resource-Release</span> <span class="pre">Support</span> <span class="pre">for</span> <span class="pre">Generators</span></code>
starting at
<a class="reference external" href="https://mail.python.org/pipermail/python-dev/2003-August/037803.html">https://mail.python.org/pipermail/python-dev/2003-August/037803.html</a></aside>
</aside>
</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-0310.rst">https://github.com/python/peps/blob/main/peps/pep-0310.rst</a></p>
<p>Last modified: <a class="reference external" href="https://github.com/python/peps/commits/main/peps/pep-0310.rst">2023-09-09 17:39:29 GMT</a></p>
</article>
<nav id="pep-sidebar">
<h2>Contents</h2>
<ul>
<li><a class="reference internal" href="#abstract">Abstract</a></li>
<li><a class="reference internal" href="#pronouncement">Pronouncement</a></li>
<li><a class="reference internal" href="#rationale">Rationale</a></li>
<li><a class="reference internal" href="#basic-syntax-and-semantics">Basic Syntax and Semantics</a></li>
<li><a class="reference internal" href="#possible-extensions">Possible Extensions</a><ul>
<li><a class="reference internal" href="#multiple-expressions">Multiple expressions</a></li>
<li><a class="reference internal" href="#exception-handling">Exception handling</a></li>
</ul>
</li>
<li><a class="reference internal" href="#implementation-notes">Implementation Notes</a></li>
<li><a class="reference internal" href="#open-issues">Open Issues</a></li>
<li><a class="reference internal" href="#alternative-ideas">Alternative Ideas</a></li>
<li><a class="reference internal" href="#backwards-compatibility">Backwards Compatibility</a></li>
<li><a class="reference internal" href="#cost-of-adoption">Cost of Adoption</a></li>
<li><a class="reference internal" href="#cost-of-non-adoption">Cost of Non-Adoption</a></li>
<li><a class="reference internal" href="#references">References</a></li>
<li><a class="reference internal" href="#copyright">Copyright</a></li>
</ul>
<br>
<a id="source" href="https://github.com/python/peps/blob/main/peps/pep-0310.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>