Add PEP 3109: Raising Exceptions in Python 3000
This commit is contained in:
parent
a2a12a86ea
commit
2b60fcad43
|
@ -107,6 +107,7 @@ Index by Category
|
|||
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
||||
S 3107 Function Annotations Winter, Lownds
|
||||
I 3108 Standard Library Reorganization Cannon
|
||||
I 3109 Raising Exceptions in Python 3000 Winter
|
||||
|
||||
Finished PEPs (done, implemented in Subversion)
|
||||
|
||||
|
@ -447,6 +448,7 @@ Numerical Index
|
|||
S 3106 Revamping dict.keys(), .values() and .items() GvR
|
||||
S 3107 Function Annotations Winter, Lownds
|
||||
I 3108 Standard Library Reorganization Cannon
|
||||
I 3109 Raising Exceptions in Python 3000 Winter
|
||||
|
||||
Key
|
||||
|
||||
|
|
|
@ -0,0 +1,286 @@
|
|||
PEP: 3109
|
||||
Title: Raising Exceptions in Python 3000
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Collin Winter <collinw@gmail.com>
|
||||
Status: Draft
|
||||
Type: Standards Track
|
||||
Content-Type: text/x-rst
|
||||
Created: 19-Jan-2006
|
||||
Python-Version: 3.0
|
||||
Post-History:
|
||||
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
This PEP introduces changes to Python's mechanisms for raising
|
||||
exceptions intended to reduce both line noise and the size of the
|
||||
language.
|
||||
|
||||
|
||||
Rationale
|
||||
=========
|
||||
|
||||
One of Python's guiding maxims is "there should be one -- and
|
||||
preferably only one -- obvious way to do it" [#zen]_. Python 2.x's
|
||||
``raise`` statement violates this principle, permitting multiple
|
||||
ways of expressing the same thought. For example, these statements
|
||||
are equivalent: ::
|
||||
|
||||
raise E, V
|
||||
|
||||
raise E(V)
|
||||
|
||||
There is a third form of the ``raise`` statement, allowing arbitrary
|
||||
tracebacks to be attached to an exception [#grammar]_: ::
|
||||
|
||||
raise E, V, T
|
||||
|
||||
where T is a traceback. As specified in PEP 344 [#pep344]_,
|
||||
exception objects in Python 3.x will possess a ``__traceback__``
|
||||
attribute, admitting this translation of the three-expression
|
||||
``raise`` statement: ::
|
||||
|
||||
raise E, V, T
|
||||
|
||||
is translated to ::
|
||||
|
||||
e = E(V)
|
||||
e.__traceback__ = T
|
||||
raise e
|
||||
|
||||
Using these translations, we can reduce the ``raise`` statement from
|
||||
four forms to two:
|
||||
|
||||
1. ``raise`` (with no arguments) is used to re-raise the active
|
||||
exception in an ``except`` suite.
|
||||
|
||||
2. ``raise EXCEPTION`` is used to raise a new exception. This form has
|
||||
two sub-variants: ``EXCEPTION`` may be an exception class or an
|
||||
instance of an exception class; valid exception classes are
|
||||
BaseException and its subclasses [#pep352]_. If ``EXCEPTION``
|
||||
is a subclass, it will be called with no arguments to obtain
|
||||
an exception instance.
|
||||
|
||||
To raise anything else is an error.
|
||||
|
||||
There is a further, more tangible benefit to be obtained through this
|
||||
consolidation, as noted by A.M. Kuchling [#amk-line-noise]_. ::
|
||||
|
||||
PEP 8 doesn't express any preference between the
|
||||
two forms of raise statements:
|
||||
raise ValueError, 'blah'
|
||||
raise ValueError("blah")
|
||||
|
||||
I like the second form better, because if the exception arguments
|
||||
are long or include string formatting, you don't need to use line
|
||||
continuation characters because of the containing parens.
|
||||
|
||||
The BDFL has concurred [#guido-declaration]_ and endorsed the
|
||||
consolidation of the several ``raise`` forms.
|
||||
|
||||
|
||||
Grammar Changes
|
||||
===============
|
||||
|
||||
In Python 3, the grammar for ``raise`` statements will change
|
||||
from [#grammar]_ ::
|
||||
|
||||
raise_stmt: 'raise' [test [',' test [',' test]]]
|
||||
|
||||
to ::
|
||||
|
||||
raise_stmt: 'raise' [test]
|
||||
|
||||
|
||||
Changes to Builtin Types
|
||||
========================
|
||||
|
||||
Because of its relation to exception raising, the signature for the
|
||||
``throw()`` method on generator objects will change, dropping the
|
||||
optional second and third parameters. The signature thus changes
|
||||
from [#throw-sig]_ ::
|
||||
|
||||
generator.throw(E, [V, [T]])
|
||||
|
||||
to ::
|
||||
|
||||
generator.throw(EXCEPTION)
|
||||
|
||||
Where ``EXCEPTION`` is either a subclass of ``BaseException`` or an
|
||||
instance of a subclass of ``BaseException``.
|
||||
|
||||
|
||||
Semantic Changes
|
||||
================
|
||||
|
||||
In Python 2, the following ``raise`` statement is legal ::
|
||||
|
||||
raise ((E1, (E2, E3)), E4), V
|
||||
|
||||
The interpreter will take the tuple's first element as the exception
|
||||
type (recursively), making the above fully equivalent to ::
|
||||
|
||||
raise E1, V
|
||||
|
||||
As of Python 3.0, support for raising tuples like this will be
|
||||
dropped. This change will bring ``raise`` statements into line with
|
||||
the ``throw()`` method on generator objects, which already disallows
|
||||
this.
|
||||
|
||||
|
||||
Compatibility Issues
|
||||
====================
|
||||
|
||||
All two- and three-expression ``raise`` statements will require
|
||||
modification, as will all two- and three-expression ``throw()`` calls
|
||||
on generators. Fortunately, the translation from Python 2.x to
|
||||
Python 3.x in this case is simple and can be handled mechanically
|
||||
by Guido van Rossum's 2to3 utility [#2to3]_ using the ``raise`` and
|
||||
``throw`` fixers ([#raise-fixer]_, [#throw-fixer]_).
|
||||
|
||||
The following translations will be performed:
|
||||
|
||||
1. Zero- and one-expression ``raise`` statements will be left
|
||||
intact.
|
||||
|
||||
2. Two-expression ``raise`` statements will be converted from ::
|
||||
|
||||
raise E, V
|
||||
|
||||
to ::
|
||||
|
||||
raise E(V)
|
||||
|
||||
Two-expression ``throw()`` calls will be converted from ::
|
||||
|
||||
generator.throw(E, V)
|
||||
|
||||
to ::
|
||||
|
||||
generator.throw(E(V))
|
||||
|
||||
See point #5 for a caveat to this transformation.
|
||||
|
||||
3. Three-expression ``raise`` statements will be converted from ::
|
||||
|
||||
raise E, V, T
|
||||
|
||||
to ::
|
||||
|
||||
e = E(V)
|
||||
e.__traceback__ = T
|
||||
raise e
|
||||
|
||||
Three-expression ``throw()`` calls will be converted from ::
|
||||
|
||||
generator.throw(E, V, T)
|
||||
|
||||
to ::
|
||||
|
||||
e = E(V)
|
||||
e.__traceback__ = T
|
||||
generator.throw(e)
|
||||
|
||||
See point #5 for a caveat to this transformation.
|
||||
|
||||
4. Two- and three-expression ``raise`` statements where ``E`` is a
|
||||
tuple literal can be converted automatically using ``2to3``'s
|
||||
``raise`` fixer. ``raise`` statements where ``E`` is a non-literal
|
||||
tuple, e.g., the result of a function call, will need to be
|
||||
converted manually.
|
||||
|
||||
5. Two- and three-expression ``raise`` statements where ``E`` is an
|
||||
exception class and ``V`` is an exception instance will need
|
||||
special attention. These cases break down into two camps:
|
||||
|
||||
1. ``raise E, V`` as a long-hand version of the zero-argument
|
||||
``raise`` statement. As an example, assuming F is a subclass
|
||||
of E ::
|
||||
|
||||
try:
|
||||
something()
|
||||
except F as V:
|
||||
raise F(V)
|
||||
except E as V:
|
||||
handle(V)
|
||||
|
||||
This would be better expressed as ::
|
||||
|
||||
try:
|
||||
something()
|
||||
except F:
|
||||
raise
|
||||
except E as V:
|
||||
handle(V)
|
||||
|
||||
2. ``raise E, V`` as a way of "casting" an exception to another
|
||||
class. Taking an example from
|
||||
distutils.compiler.unixcompiler ::
|
||||
|
||||
try:
|
||||
self.spawn(pp_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError(msg)
|
||||
|
||||
This would be better expressed as ::
|
||||
|
||||
try:
|
||||
self.spawn(pp_args)
|
||||
except DistutilsExecError as msg:
|
||||
raise CompileError from msg
|
||||
|
||||
Using the ``raise ... from ...`` syntax introduced in
|
||||
PEP 344.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [#zen]
|
||||
http://www.python.org/dev/peps/pep-0020/
|
||||
|
||||
.. [#grammar]
|
||||
http://www.python.org/doc/current/ref/raise.html
|
||||
|
||||
.. [#throw-sig]
|
||||
http://www.python.org/dev/peps/pep-0342/
|
||||
|
||||
.. [#pep344]
|
||||
http://www.python.org/dev/peps/pep-0344/
|
||||
|
||||
.. [#pep352]
|
||||
http://www.python.org/dev/peps/pep-0352/
|
||||
|
||||
.. [#amk-line-noise]
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055187.html
|
||||
|
||||
.. [#guido-declaration]
|
||||
http://mail.python.org/pipermail/python-dev/2005-August/055190.html
|
||||
|
||||
.. [#2to3]
|
||||
http://svn.python.org/view/sandbox/trunk/2to3/
|
||||
|
||||
.. [#raise-fixer]
|
||||
http://svn.python.org/view/sandbox/trunk/2to3/fixes/fix_raise.py
|
||||
|
||||
.. [#throw-fixer]
|
||||
http://svn.python.org/view/sandbox/trunk/2to3/fixes/fix_throw.py
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
||||
|
||||
|
||||
..
|
||||
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