PEP 601: Fix footnotes (#2736)
Co-authored-by: CAM Gerlach <CAM.Gerlach@Gerlach.CAM>
This commit is contained in:
parent
b1ab534da6
commit
3a79e80801
103
pep-0601.txt
103
pep-0601.txt
|
@ -25,21 +25,21 @@ is a conditional return (or break etc.) inside a finally block.".
|
|||
Abstract
|
||||
========
|
||||
|
||||
This PEP proposes to forbid return, break and continue statements within
|
||||
a finally suite where they would break out of the finally. Their use in
|
||||
This PEP proposes to forbid ``return``, ``break`` and ``continue`` statements within
|
||||
a ``finally`` suite where they would break out of the ``finally``. Their use in
|
||||
such a location silently cancels any active exception being raised through
|
||||
the finally, leading to unclear code and possible bugs.
|
||||
the ``finally``, leading to unclear code and possible bugs.
|
||||
|
||||
Continue is currently not supported in a finally in Python 3.7 (due to
|
||||
``continue`` is currently not supported in a ``finally`` in Python 3.7 (due to
|
||||
implementation issues) and the proposal is to not add support for it in
|
||||
Python 3.8. For return and break the proposal is to deprecate their use
|
||||
Python 3.8. For ``return`` and ``break`` the proposal is to deprecate their use
|
||||
in Python 3.9, emit a compilation warning in Python 3.10 and then forbid
|
||||
their use after that.
|
||||
|
||||
Motivation
|
||||
==========
|
||||
|
||||
The use of return, break and continue within a finally suite leads to behaviour
|
||||
The use of ``return``, ``break`` and ``continue`` within a ``finally`` suite leads to behaviour
|
||||
which is not at all obvious. Consider the following function::
|
||||
|
||||
def foo():
|
||||
|
@ -49,9 +49,9 @@ which is not at all obvious. Consider the following function::
|
|||
return
|
||||
|
||||
This will return cleanly (without an exception) even though it has infinite
|
||||
recursion and raises an exception within the try. The reason is that the return
|
||||
within the finally will silently cancel any exception that propagates through
|
||||
the finally suite. Such behaviour is unexpected and not at all obvious.
|
||||
recursion and raises an exception within the ``try``. The reason is that the ``return``
|
||||
within the ``finally`` will silently cancel any exception that propagates through
|
||||
the ``finally`` suite. Such behaviour is unexpected and not at all obvious.
|
||||
This function is equivalent to::
|
||||
|
||||
def foo():
|
||||
|
@ -61,8 +61,8 @@ This function is equivalent to::
|
|||
pass
|
||||
return
|
||||
|
||||
Break and continue have similar behaviour (they silence exceptions) if they
|
||||
jump to code outside the finally suite. For example::
|
||||
``break`` and ``continue`` have similar behaviour (they silence exceptions) if they
|
||||
jump to code outside the ``finally`` suite. For example::
|
||||
|
||||
def bar():
|
||||
while True:
|
||||
|
@ -83,35 +83,35 @@ This behaviour goes against the following parts of The Zen of Python:
|
|||
If this behaviour of silencing exceptions is really needed then the explicit
|
||||
form of a try-except can be used instead, and this makes the code clearer.
|
||||
|
||||
Independent to the semantics, implementing return/break/continue within a
|
||||
finally suite is non-trivial as it requires to correctly track any active
|
||||
exceptions at runtime (an executing finally suite may or may not have an
|
||||
Independent to the semantics, implementing ``return``/``break``/``continue`` within a
|
||||
``finally`` suite is non-trivial as it requires to correctly track any active
|
||||
exceptions at runtime (an executing ``finally`` suite may or may not have an
|
||||
active exception) and cancel them as appropriate. CPython did have a bug in
|
||||
this for the case of continue and so originally disallowed it [1]. Requiring
|
||||
correct behaviour for return/break/continue within a finally puts an
|
||||
this for the case of ``continue`` and so originally disallowed it [1]_. Requiring
|
||||
correct behaviour for ``return``/``break``/``continue`` within a ``finally`` puts an
|
||||
unnecessary burden on alternative implementations of Python.
|
||||
|
||||
Other languages
|
||||
===============
|
||||
|
||||
Java allows to return from within a finally block, but its use is discouraged
|
||||
according to [2], [3], [4]. The Java compiler later on included a linting
|
||||
option -Xlint:finally to warn against the use of return within a finally block.
|
||||
Java allows to return from within a ``finally`` block, but its use is discouraged
|
||||
according to [2]_, [3]_, [4]_. The Java compiler later on included a linting
|
||||
option ``-Xlint:finally`` to warn against the use of return within a ``finally`` block.
|
||||
The Eclipse editor also warns about this use.
|
||||
|
||||
Ruby allows return from inside ensure (Python's finally), but it should be an
|
||||
explicit return. It is discouraged and handled by linters [5], [6].
|
||||
explicit return. It is discouraged and handled by linters [5]_, [6]_.
|
||||
|
||||
Like Ruby, JavaScript also allows use of return/break/continue within a finally
|
||||
but it is seen as unsafe and it is handled by eslint [7].
|
||||
Like Ruby, JavaScript also allows use of ``return``/``break``/``continue`` within a ``finally``
|
||||
but it is seen as unsafe and it is handled by eslint [7]_.
|
||||
|
||||
C# forbids the use of ending statements like return/goto/break within a finally
|
||||
[8], [9].
|
||||
C# forbids the use of ending statements like ``return``/``goto``/``break`` within a ``finally``
|
||||
[8]_, [9]_.
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
Since the behaviour of return/break/continue within a finally is unclear, the
|
||||
Since the behaviour of ``return``/``break``/``continue`` within a ``finally`` is unclear, the
|
||||
pattern is rarely used, and there is a simple alternative to writing equivalent
|
||||
code (which is more explicit), forbidding the syntax is the most straightforward
|
||||
approach.
|
||||
|
@ -120,18 +120,18 @@ Specification
|
|||
=============
|
||||
|
||||
This is a change to the compiler, not the grammar. The compiler should
|
||||
check for the following in a finally suite:
|
||||
check for the following in a ``finally`` suite:
|
||||
|
||||
* A return in any statement, at any level of nesting.
|
||||
* A ``return`` in any statement, at any level of nesting.
|
||||
|
||||
* A break/continue in any statement, at any level of nesting, that would
|
||||
transfer control flow outside the finally suite.
|
||||
* A ``break``/``continue`` in any statement, at any level of nesting, that would
|
||||
transfer control flow outside the ``finally`` suite.
|
||||
|
||||
Upon finding such a case it should emit the appropriate exception:
|
||||
|
||||
* For continue, a SyntaxError (this is the current behaviour of 3.7).
|
||||
* For ``continue``, a ``SyntaxError`` (this is the current behaviour of 3.7).
|
||||
|
||||
* For return/break, a SyntaxWarning in 3.10, and a SyntaxError after that.
|
||||
* For ``return``/``break``, a ``SyntaxWarning`` in 3.10, and a ``SyntaxError`` after that.
|
||||
|
||||
For example, the following are all forbidden by this proposal::
|
||||
|
||||
|
@ -160,8 +160,8 @@ For example, the following are all forbidden by this proposal::
|
|||
for x in range(10):
|
||||
return
|
||||
|
||||
The following is still allowed because the continue doesn't escape the
|
||||
finally::
|
||||
The following is still allowed because the ``continue`` doesn't escape the
|
||||
``finally``::
|
||||
|
||||
try:
|
||||
pass
|
||||
|
@ -169,17 +169,17 @@ finally::
|
|||
for x in range(10):
|
||||
continue
|
||||
|
||||
Note that yielding from within a finally remains acceptable by this PEP
|
||||
because resuming the generator will resume the finally and eventually
|
||||
Note that yielding from within a ``finally`` remains acceptable by this PEP
|
||||
because resuming the generator will resume the ``finally`` and eventually
|
||||
raise any active exceptions (so they are never silenced by yielding).
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
This is a backwards incompatible change, for return and break.
|
||||
This is a backwards incompatible change, for ``return`` and ``break``.
|
||||
|
||||
The following locations in the CPython standard library (at
|
||||
v3.8.0b1-651-g7fcc2088a5) use return within finally:
|
||||
v3.8.0b1-651-g7fcc2088a5) use ``return`` within ``finally``:
|
||||
|
||||
* Lib/subprocess.py:921 - the use here looks like a bug
|
||||
|
||||
|
@ -189,11 +189,11 @@ v3.8.0b1-651-g7fcc2088a5) use return within finally:
|
|||
* Lib/multiprocessing/connection.py:318 - the use here looks legitimate
|
||||
but the intention is not clear
|
||||
|
||||
* Lib/test/test_sys_settrace.py:837 - a test for return within finally
|
||||
* Lib/test/test_sys_settrace.py:837 - a test for ``return`` within ``finally``
|
||||
|
||||
* Lib/test/test_sys_settrace.py:1346 - a test for return within finally
|
||||
* Lib/test/test_sys_settrace.py:1346 - a test for ``return`` within ``finally``
|
||||
|
||||
There are no uses of break within a finally (that break out of the finally)
|
||||
There are no uses of ``break`` within a ``finally`` (that break out of the ``finally``)
|
||||
in the standard library.
|
||||
|
||||
Security Implications
|
||||
|
@ -208,19 +208,19 @@ How to Teach This
|
|||
This feature is very rarely used so forbidding it will likely only impact
|
||||
advanced users, not beginners and probably not any existing teaching
|
||||
material. Since this is the removal of a feature teaching users will be
|
||||
one by the raising of a SyntaxError if/when the forbidden feature is used.
|
||||
one by the raising of a ``SyntaxError`` if/when the forbidden feature is used.
|
||||
|
||||
Reference Implementation
|
||||
========================
|
||||
|
||||
There is currently no reference implementation, although the way continue
|
||||
is currently handled in a finally (raising a SyntaxError) can be extended
|
||||
to return and break.
|
||||
is currently handled in a ``finally`` (raising a ``SyntaxError``) can be extended
|
||||
to ``return`` and ``break``.
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [1] https://bugs.python.org/issue37830
|
||||
.. [1] https://github.com/python/cpython/issues/82011
|
||||
|
||||
.. [2] https://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java
|
||||
|
||||
|
@ -228,9 +228,9 @@ References
|
|||
|
||||
.. [4] https://wiki.sei.cmu.edu/confluence/display/java/ERR04-J.+Do+not+complete+abruptly+from+a+finally+block
|
||||
|
||||
.. [5] https://github.com/rubocop-hq/rubocop/issues/5949
|
||||
.. [5] https://github.com/rubocop/rubocop/issues/5949
|
||||
|
||||
.. [6] https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Lint/EnsureReturn
|
||||
.. [6] https://www.rubydoc.info/gems/rubocop/0.74.0/RuboCop/Cop/Lint/EnsureReturn
|
||||
|
||||
.. [7] https://eslint.org/docs/rules/no-unsafe-finally
|
||||
|
||||
|
@ -243,14 +243,3 @@ Copyright
|
|||
|
||||
This document is placed in the public domain or under the
|
||||
CC0-1.0-Universal license, whichever is more permissive.
|
||||
|
||||
|
||||
|
||||
..
|
||||
Local Variables:
|
||||
mode: indented-text
|
||||
indent-tabs-mode: nil
|
||||
sentence-end-double-space: t
|
||||
fill-column: 70
|
||||
coding: utf-8
|
||||
End:
|
||||
|
|
Loading…
Reference in New Issue