Revised based on Guido's wishes: no more TerminatingException and bare 'except'
clauses act like ``except Exception``. Transition plan completely reworked to basically not go through hoops that will negatively impact performance. Basically now BaseException is added and everything else is not changed until Python 3.0 . Also suggests docs be changed to suggest a certain practice.
This commit is contained in:
parent
239f9ff186
commit
94c0ae0d20
296
pep-0348.txt
296
pep-0348.txt
|
@ -9,6 +9,8 @@ Content-Type: text/x-rst
|
|||
Created: 28-Jul-2005
|
||||
Post-History:
|
||||
|
||||
.. |2.x| replace:: 2.5
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
@ -26,11 +28,10 @@ superclass is proposed. This is to have guarantees about the basic
|
|||
interface of exceptions and to further enhance the natural hierarchy
|
||||
of exceptions.
|
||||
|
||||
Lastly, bare ``except`` clauses will be removed. While they had their
|
||||
usefulness when exceptions could be any object, with the above
|
||||
proposal
|
||||
of a required superclass for exceptions bare ``except`` clauses lose
|
||||
their purpose.
|
||||
Lastly, bare ``except`` clauses will be changed to be semantically
|
||||
equivalent to ``except Exception``. Most people currently use bare
|
||||
``except`` clause for this purpose and with the exception hierarchy
|
||||
reorganization becomes a viable default.
|
||||
|
||||
|
||||
Rationale For Wanting Change
|
||||
|
@ -48,17 +49,19 @@ raised objects might adhere to.
|
|||
|
||||
But exceptions do have a hierarchy, showing the severity of the
|
||||
exception. The hierarchy also groups related exceptions together to
|
||||
simplify catching them in ``except`` clauses. To allow peopele to
|
||||
simplify catching them in ``except`` clauses. To allow people to
|
||||
be able to rely on this hierarchy, a common superclass that all
|
||||
raise objects must inherit from is being proposed. It also allows
|
||||
guarantees about the interface to raised objects to be made (see
|
||||
PEP 344 [#PEP344]_). A discussion about all of this has occurred
|
||||
before on python-dev [#Summary2004-08-01]_.
|
||||
|
||||
With the requirement of a common superclass for all exceptions, bare
|
||||
``except`` clauses are impacted. Currently used as a catch-all for
|
||||
raised exceptions, its usefulness is terminally weakened. Now, the
|
||||
same functionality is possible by catching the required superclass.
|
||||
As bare ``except`` clauses stand now, they catch *all* exceptions.
|
||||
While this can be handy, it is rather overreaching for the common
|
||||
case. Thanks to having a required superclass, catching all
|
||||
exceptions is as easy as catching just one specific exception.
|
||||
This allows bare ``except`` clauses to be used for a more useful
|
||||
purpose.
|
||||
Once again, this has been discussed on python-dev [#python-dev3]_.
|
||||
|
||||
Finally, slight changes to the exception hierarchy will make it much
|
||||
|
@ -74,7 +77,9 @@ Philosophy of Reorganization
|
|||
For the reorganization of the hierarchy, there was a general
|
||||
philosophy followed that developed from discussion of earlier drafts
|
||||
of this PEP [#python-dev-thread1]_, [#python-dev-thread2]_,
|
||||
[#python-dev-thread3]_. First and foremost was to not break anything
|
||||
[#python-dev-thread3]_, [#python-dev-thread4]_,
|
||||
[#python-dev-thread5]_, [#python-dev-thread6]_.
|
||||
First and foremost was to not break anything
|
||||
that works. This meant that renaming exceptions was out of the
|
||||
question unless the name was deemed severely bad. This
|
||||
also meant no removal of exceptions unless they were viewed as
|
||||
|
@ -152,10 +157,8 @@ New Hierarchy
|
|||
+-- SyntaxWarning
|
||||
+-- UserWarning
|
||||
+ -- WindowsError
|
||||
+-- TerminatingException (new; stricter inheritance for
|
||||
subclasses)
|
||||
+-- KeyboardInterrupt
|
||||
+-- SystemExit
|
||||
+-- KeyboardInterrupt (stricter inheritance)
|
||||
+-- SystemExit (stricter inheritance)
|
||||
|
||||
|
||||
Differences Compared to Python 2.4
|
||||
|
@ -190,79 +193,14 @@ exceptions should be caught blindly, ``except BaseException`` will
|
|||
work.
|
||||
|
||||
|
||||
TerminatingException
|
||||
--------------------
|
||||
KeyboardInterrupt and SystemExit
|
||||
--------------------------------
|
||||
|
||||
Superclass for exceptions that are meant to symbolize the termination
|
||||
of
|
||||
the interpreter. It does not inherit from Exception so that the
|
||||
common
|
||||
``except Exception`` statement does not catch the exceptions. This
|
||||
for ``try`` statements that want to catch all exceptions that are
|
||||
signals of errors and handle them separately from exceptions that
|
||||
signify that the interpreter should be terminated::
|
||||
|
||||
try:
|
||||
...
|
||||
# Catch all exceptions that are expected to be caught
|
||||
except Exception:
|
||||
...
|
||||
# Catch exceptions expected to terminate the interpreter
|
||||
except TerminatingException:
|
||||
...
|
||||
|
||||
Compare this to::
|
||||
|
||||
try:
|
||||
...
|
||||
except Exception:
|
||||
...
|
||||
except (KeyboardInterrupt, SystemExit):
|
||||
...
|
||||
|
||||
While more explicit, it is not necessarily obvious why the two
|
||||
exceptions are being caught directly. By providing a common
|
||||
superclass with a name that explicitly states the exceptions' typical
|
||||
usage the reasoning behind the catch becomes more apparent.
|
||||
|
||||
Comparing it to an even more general ``except`` clause::
|
||||
|
||||
try:
|
||||
...
|
||||
except Exception:
|
||||
...
|
||||
except BaseException:
|
||||
...
|
||||
|
||||
While this will perform the same action and catch all exceptions,
|
||||
guaranteed, it is once again not obvious why Exception and
|
||||
BaseException are being caught separately and not just
|
||||
BaseException based purely on the code.
|
||||
|
||||
TerminatingException will also help with transitioning from Python
|
||||
2.x to 3.0 . With TerminatingException being a new exception, when
|
||||
it is used the new inheritance for KeyboardInterrupt and SystemExit
|
||||
becomes more obvious.
|
||||
|
||||
It has been argued that TerminatingException should not be added
|
||||
because it goes against Flat Is Better Than Nested (FIBTN).
|
||||
While this new exception will not make the hierarchy as flat is it
|
||||
could be, the overall depth of the tree is not changed; Exception has
|
||||
a much deeper inheritance tree below it.
|
||||
|
||||
It has also been argued that since KeyboardInterrupt and SystemExit
|
||||
are not caught together that often in 2.4, there might not be much of
|
||||
a need for TerminatingException. But with their new position in the
|
||||
hierarchy catching them separately from other exceptions should
|
||||
become more prevalent.
|
||||
|
||||
Naming is based on the idea that the interpreter is trying to
|
||||
terminate when KeyboardInterrupt and SystemExit
|
||||
are raised. An earlier proposal suggested
|
||||
"TerminalException" but
|
||||
avoidance of any confusion with an actual terminal along with
|
||||
"terminal" being
|
||||
more fatalistic than "terminating" led to the current name choice.
|
||||
Both exceptions are no longer under Exception. This is to allow bare
|
||||
``except`` clauses to act as a more viable default case by catching
|
||||
exceptions that inherit from Exception. With both KeyboardInterrupt
|
||||
and SystemExit acting as signals that the interpreter is expected to
|
||||
exit, catching them in the common case is the wrong semantics.
|
||||
|
||||
|
||||
NotImplementedError
|
||||
|
@ -298,140 +236,69 @@ For the C API, all functions that set an exception will have the same
|
|||
inheritance check applied.
|
||||
|
||||
|
||||
Removal of Bare ``except`` Clauses
|
||||
==================================
|
||||
Bare ``except`` Clauses Catch Exception
|
||||
=======================================
|
||||
|
||||
Bare ``except`` clauses serve the purpose of catching all exceptions
|
||||
in Python 2.x . This is needed thanks to the fact that in 2.x any
|
||||
exception can be raised as an exception. But if this PEP is accepted
|
||||
this will no longer be the case because of a required superclass for
|
||||
all raised objects.
|
||||
This goes against a part of the Zen of Python;
|
||||
One Way To Do It (OWTDI) [#zen]_. By having bare ``except`` clauses
|
||||
keep their semantic meaning, there would be two ways of doing the
|
||||
same things. It also goes against Exlpicit Is Better Than Implicit
|
||||
(EIBTI) by implicitly doing something that can easily be covered by
|
||||
a more explicit statement.
|
||||
In most existing Python 2.4 code, bare ``except`` clauses are too
|
||||
broad in the exceptions they catch. Typically only exceptions that
|
||||
signal an error are desired to be caught. This means that exceptions
|
||||
that are used to signify that the interpreter should exit should not
|
||||
be caught in the common case.
|
||||
|
||||
It has also been proposed that bare ``except`` clauses be changed to
|
||||
semantically be equivalent to ``except Exception``. This has been
|
||||
proposed since this is what most bare ``except`` clauses are meant to
|
||||
do. This would make ``except`` clauses have a more reasonable
|
||||
default behavior.
|
||||
With KeyboardInterrupt and SystemExit moved to inherit from
|
||||
BaseException instead of Exception, changing bare ``except`` clauses
|
||||
to act as ``except Exception`` becomes a much more reasonable
|
||||
default. This change also will break very little code since these
|
||||
semantics are what most people want for bare ``except`` clauses.
|
||||
|
||||
But this line of reasoning has some issues. First is that it also
|
||||
goes against the Zen of Python; both OWTDI and EIBTI by providing
|
||||
an implicit alternative to ``except Exception``. Secondly,
|
||||
backwards-compatibility becomes more difficult. While removal will
|
||||
break code, it can mechanically be changed to have the same semantic
|
||||
meaning as it currently has by finding all occurances of ``except:``
|
||||
and replacing them with ``except BaseException:``. But going with
|
||||
this semantic change makes compatibility more subtle. Was a bare
|
||||
``except`` clause meant to catch all exceptions, or actually meant
|
||||
to catch all reasonable exceptions (i.e., everything but
|
||||
TerminatingException)? Every case will need to be carefully
|
||||
examined, and could easily be incorrectly examined, leading to subtle
|
||||
bugs.
|
||||
|
||||
The shorter typing afforded by bare ``except`` statements also does
|
||||
not justify its existence. "Exception", the typical exception that\
|
||||
will be caught, is only nine characters. Add in the needed space to
|
||||
separate "Exception" from "except" you get only 10 more characters to
|
||||
type. While this might be a nuisance in quick-and-dirty scripts, the
|
||||
impact is minimal.
|
||||
The complete removal of bare ``except`` clauses has been argued for.
|
||||
The case has been made that they violate both Only One Way To Do It
|
||||
(OOWTDI) and Explicit Is Better Than Implicit (EIBTI) as listed in the
|
||||
Zen of Python [#zen]_. But Practicality Beats Purity (PBP), also in
|
||||
the Zen of Python, trumps both of these in this case. The BDFL has
|
||||
stated that bare ``except`` clauses will work this way
|
||||
[#python-dev8]_.
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
Changing Grammar/Grammar is all that is needed to remove bare
|
||||
``except`` clauses.
|
||||
The compiler will emit the bytecode for ``except Exception`` whenever
|
||||
a bare ``except`` clause is reached.
|
||||
|
||||
|
||||
Transition Plan
|
||||
===============
|
||||
|
||||
Exception Hierarchy Changes
|
||||
---------------------------
|
||||
Because of the complexity and clutter that would be required to add
|
||||
all features planned in this PEP, the transition plan is very simple.
|
||||
In Python |2.x| BaseException is added. In Python 3.0, all remaining
|
||||
features (required superclass, change in inheritance, bare ``except``
|
||||
clauses becoming the same as ``except Exception``) will go into
|
||||
affect. In order to make all of this work in a backwards-compatible
|
||||
way in Python |2.x| would require very deep hacks in the exception
|
||||
machinery which could be error-prone and lead to a slowdown in
|
||||
performance for little benefit.
|
||||
|
||||
New Exceptions
|
||||
''''''''''''''
|
||||
To help with the transition, the documentation will be changed to
|
||||
reflect several programming guidelines:
|
||||
|
||||
New exceptions can simply be added to the built-in namespace. Any
|
||||
pre-existing objects with the same name will mask the new exceptions,
|
||||
preserving backwards-compatibility.
|
||||
- When one wants to catch *all* exceptions, catch BaseException
|
||||
- To catch all exceptions that do not represent the termination of
|
||||
the interpreter, catch Exception explicitly
|
||||
- Explicitly catch KeyboardInterrupt and SystemExit; don't rely on
|
||||
inheritance from Exception to lead to the capture
|
||||
- Always catch NotImplementedError explicitly instead of relying on
|
||||
the inheritance from RuntimeError
|
||||
|
||||
|
||||
New Inheritance for Old Exceptions
|
||||
''''''''''''''''''''''''''''''''''
|
||||
|
||||
Using multiple inheritance to our advantage, exceptions whose
|
||||
inheritance is now more resrictive can be made backwards-compatible.
|
||||
By inheriting from both the new superclasses as well as the original
|
||||
superclasses, existing ``except`` clauses will continue to work as
|
||||
before while allowing the new inheritance to be used for new code.
|
||||
|
||||
A PendingDeprecationWarning will be raised based on whether the
|
||||
bytecode ``COMPARE_OP(10)`` results in an exception being caught that
|
||||
would not have under the new hierarchy. This will require hard-coding
|
||||
in the implementation of the bytecode.
|
||||
|
||||
|
||||
Required Superclass for ``raise``
|
||||
---------------------------------
|
||||
|
||||
A DeprecationWarning will be raised when an object is passed to
|
||||
``raise`` that does not have the proper inheritance.
|
||||
|
||||
|
||||
Removal of Bare ``except`` Clauses
|
||||
----------------------------------
|
||||
|
||||
A PendingDeprecationWarning will be raised when a bare ``except``
|
||||
clause is found in code. One release before they are removed the
|
||||
warning will be changed to DeprecationWarning.
|
||||
|
||||
Doing ``from __future__ import exceptions`` will cause bare
|
||||
``except`` clauses to be considered syntax errors.
|
||||
|
||||
|
||||
Roadmap
|
||||
-------
|
||||
|
||||
Python 2.x is the first version that contains changes. Python 3.0
|
||||
will be when transition will be complete. Version 3.0-1 represents
|
||||
one version before 3.0 is released, 3.0-2 two versions before, etc.
|
||||
|
||||
* 2.x
|
||||
- Add BaseException, TerminatingException
|
||||
- Have KeyboardInterrupt and SystemExit inherit from both
|
||||
Exception and TerminatingException
|
||||
- Introduce ``from __future__ import exceptions``
|
||||
- Provide a script that mechanically changes all bare ``except``
|
||||
clauses to catch BaseException in a .py file
|
||||
- PendingDeprecationWarning for bare ``except`` clauses
|
||||
- PendingDeprecationWarning for all objects raised that do not
|
||||
inherit from BaseException
|
||||
- PendingDeprecationWarning raised when KeyboardInterrupt or
|
||||
SystemExit are caught because of their inheritance of Exception
|
||||
* 3.0-1
|
||||
- Turn all introduced PendingDeprecationWarnings into
|
||||
DeprecationWarning
|
||||
* 3.0
|
||||
- Remove DeprecationWarnings
|
||||
- Have KeyboardInterrupt and SystemExit only inherit from
|
||||
TerminatingException
|
||||
- Remove ``exceptions`` __future__ import support
|
||||
The documentation for the 'exceptions' module [#exceptions-stdlib]_,
|
||||
tutorial [#tutorial]_, and PEP 290 [#PEP290]_ will all require
|
||||
updating.
|
||||
|
||||
|
||||
Rejected Ideas
|
||||
==============
|
||||
|
||||
Multiple threads on python-dev discussing this PEP have lead to
|
||||
various ideas being rejected [#python-dev-thread1]_,
|
||||
[#python-dev-thread2]_, [#python-dev-thread3]_.
|
||||
|
||||
|
||||
DeprecationWarning Inheriting From PendingDeprecationWarning
|
||||
------------------------------------------------------------
|
||||
|
||||
|
@ -553,6 +420,17 @@ It turns out, though, enough code exists that uses the exception to
|
|||
warrant it staying.
|
||||
|
||||
|
||||
Superclass for KeyboardInterrupt and SystemExit
|
||||
-----------------------------------------------
|
||||
|
||||
Proposed to make catching non-Exception inheriting exceptions easier
|
||||
along with easing the transition to the new hierarchy, the idea was
|
||||
rejected by the BDFL [#python-dev8]_. The argument that existing
|
||||
code did not show enough instances of the pair of exceptions being
|
||||
caught and thus did not justify cluttering the built-in namespace
|
||||
was used.
|
||||
|
||||
|
||||
Acknowledgements
|
||||
================
|
||||
|
||||
|
@ -572,6 +450,9 @@ References
|
|||
.. [#PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks)
|
||||
http://www.python.org/peps/pep-0344.html
|
||||
|
||||
.. [#PEP290] PEP 290 (Code Migration and Modernization)
|
||||
http://www.python.org/peps/pep-0290.html
|
||||
|
||||
.. [#Summary2004-08-01] python-dev Summary (An exception is an
|
||||
exception, unless it doesn't inherit from Exception)
|
||||
http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception
|
||||
|
@ -595,6 +476,15 @@ References
|
|||
.. [#python-dev-thread3] python-dev thread (Reorg PEP checked in)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055138.html
|
||||
|
||||
.. [#python-dev-thread4] python-dev thread (Major revision of PEP 348 committed)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055199.html
|
||||
|
||||
.. [#python-dev-thread5] python-dev thread (Exception Reorg PEP revised yet again)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055292.html
|
||||
|
||||
.. [#python-dev-thread6] python-dev thread (PEP 348 (exception reorg) revised again)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055412.html
|
||||
|
||||
.. [#python-dev4] python-dev email (Pre-PEP: Exception Reorganization
|
||||
for Python 3.0)
|
||||
http://mail.python.org/pipermail/python-dev/2005-July/055019.html
|
||||
|
@ -609,9 +499,15 @@ References
|
|||
.. [#python-dev7] python-dev email (Exception Reorg PEP checked in)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055175.html
|
||||
|
||||
.. [#python-dev8] python-dev email (PEP 348 (exception reorg) revised again)
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055423.html
|
||||
|
||||
.. [#zen] PEP 20 (The Zen of Python)
|
||||
http://www.python.org/peps/pep-0020.html
|
||||
|
||||
.. [#tutorial] Python Tutorial
|
||||
http://docs.python.org/tut/tut.html
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
|
Loading…
Reference in New Issue