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:
Brett Cannon 2005-08-16 06:21:51 +00:00
parent 239f9ff186
commit 94c0ae0d20
1 changed files with 96 additions and 200 deletions

View File

@ -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
=========