234 lines
8.0 KiB
Plaintext
234 lines
8.0 KiB
Plaintext
|
PEP: 352
|
|||
|
Title: Required Superclass for Exceptions
|
|||
|
Version: $Revision: 1.5 $
|
|||
|
Last-Modified: $Date: 2005/06/07 13:17:37 $
|
|||
|
Author: Brett Cannon <brett@python.org>, Guido van Rossum <guido@python.org>
|
|||
|
Status: Draft
|
|||
|
Type: Standards Track
|
|||
|
Content-Type: text/x-rst
|
|||
|
Created: 27-Oct-2005
|
|||
|
Post-History:
|
|||
|
|
|||
|
|
|||
|
Abstract
|
|||
|
========
|
|||
|
|
|||
|
In Python 2.4 and before, any (classic) class can be raised as an
|
|||
|
exception. The plan is to allow new-style classes starting in Python
|
|||
|
2.5, but this makes the problem worse -- it would mean *any* class (or
|
|||
|
instance) can be raised! This is a problem since it prevents any
|
|||
|
guarantees to be made about the interface of exceptions. This PEP
|
|||
|
proposes introducing a new superclass that all raised objects must
|
|||
|
inherit from. Imposing the restriction will allow a standard
|
|||
|
interface for exceptions to exist that can be relied upon.
|
|||
|
|
|||
|
On might counter that requiring a specific base class for a particular
|
|||
|
interface is unPythonic. However, in the specific case of exceptions
|
|||
|
there's a good reason (which has generally been agreed to on
|
|||
|
python-dev): requiring hierarchy helps code that wants to *catch*
|
|||
|
exceptions by making it possible to catch *all* exceptions explicitly
|
|||
|
by writing ``except BaseException:`` instead of
|
|||
|
``except *:``. [#hierarchy-good]_
|
|||
|
|
|||
|
Introducing a new superclass for exceptions also gives us the chance
|
|||
|
to rearrange the exception hierarchy slightly for the better. As it
|
|||
|
currently stands, all exceptions in the built-in namespace inherit
|
|||
|
from Exception. This is a problem since this includes two exceptions
|
|||
|
(KeyboardInterrupt and SystemExit) that are usually meant to signal
|
|||
|
that the interpreter should be shut down. Changing it so that these
|
|||
|
two exceptions inherit from the common superclass instead of Exception
|
|||
|
will make it easy for people to write ``except`` clauses that are not
|
|||
|
overreaching and not catch exceptions that should propagate up and
|
|||
|
terminate the interpreter.
|
|||
|
|
|||
|
This PEP is based on previous work done for PEP 348 [#pep348]_.
|
|||
|
|
|||
|
|
|||
|
Requiring a Common Superclass
|
|||
|
=============================
|
|||
|
|
|||
|
This PEP proposes introducing a new exception named BaseException that
|
|||
|
is a new-style class and has a single attribute, ``message``::
|
|||
|
|
|||
|
class BaseException(object):
|
|||
|
|
|||
|
"""Superclass representing the base of the exception hierarchy.
|
|||
|
|
|||
|
Provides a 'message' attribute that contains any argument
|
|||
|
passed in during instantiation.
|
|||
|
|
|||
|
The 'args' attribute and __getitem__ method are provided for
|
|||
|
backwards-compatibility and will be deprecated at some point.
|
|||
|
|
|||
|
"""
|
|||
|
|
|||
|
def __init__(self, message='', *args):
|
|||
|
"""Set 'message' and 'args' attribute"""
|
|||
|
self.message = message
|
|||
|
self.args = (message,)
|
|||
|
if args:
|
|||
|
self.args += args
|
|||
|
|
|||
|
def __str__(self):
|
|||
|
"""Return the str of 'message'"""
|
|||
|
if len(self.args) > 1:
|
|||
|
return str(self.args)
|
|||
|
else:
|
|||
|
return str(self.message)
|
|||
|
|
|||
|
def __unicode__(self):
|
|||
|
"""Return the unicode of 'message'"""
|
|||
|
if len(self.args) > 1:
|
|||
|
return unicode(self.args)
|
|||
|
else:
|
|||
|
return unicode(self.message)
|
|||
|
|
|||
|
def __repr__(self):
|
|||
|
if len(self.args) > 1:
|
|||
|
args_repr = "*%s" % self.args
|
|||
|
else:
|
|||
|
args_repr = repr(self.message)
|
|||
|
return "%s(%s)" % (self.__class__.__name__, args_repr)
|
|||
|
|
|||
|
def __getitem__(self, index):
|
|||
|
"""Index into arguments passed in during instantiation.
|
|||
|
|
|||
|
Provided for backwards-compatibility and will be
|
|||
|
deprecated.
|
|||
|
|
|||
|
"""
|
|||
|
if index == 0:
|
|||
|
return self.message
|
|||
|
else:
|
|||
|
return self.args[index-1]
|
|||
|
|
|||
|
|
|||
|
The ``message`` attribute will contain either the argument passed in
|
|||
|
at instantiation of the object or the empty string. The attribute is
|
|||
|
meant to act as a common location to store any extra information that
|
|||
|
is to be passed along with the exception that goes beyond the location
|
|||
|
of the exception within the exception hierarchy and the exception's
|
|||
|
type.
|
|||
|
|
|||
|
No restriction is placed upon what may be passed in for ``messsage``.
|
|||
|
This provides backwards-compatibility with how the argument passed
|
|||
|
into Exception has no restrictions.
|
|||
|
|
|||
|
The ``args`` attribute is to be deprecated. While allowing multiple
|
|||
|
arguments to be passed can be helpful, it is in no way essential. It
|
|||
|
also does not make it necessarily clear which argument is going to be
|
|||
|
represented by the ``__str__`` method. Restricting to a single
|
|||
|
argument keeps the API simple and clear. This also means providing a
|
|||
|
``__getitem__`` method is unneeded for exceptions and thus will be
|
|||
|
deprecated as well.
|
|||
|
|
|||
|
The ``raise`` statement will be changed to require that any object
|
|||
|
passed to it must inherit from BaseException. This will make sure
|
|||
|
that all exceptions fall within a single hierarchy that is anchored at
|
|||
|
BaseException [#hierarchy-good]_. This also guarantees a basic
|
|||
|
interface that is inherited from BaseException. The change to
|
|||
|
``raise`` will be enforced starting in Python 3.0 (see the `Transition
|
|||
|
Plan`_ below).
|
|||
|
|
|||
|
With BaseException being the root of the exception hierarchy,
|
|||
|
Exception will now inherit from it.
|
|||
|
|
|||
|
|
|||
|
Exception Hierarchy Changes
|
|||
|
===========================
|
|||
|
|
|||
|
With the exception hierarchy now even more important since it has a
|
|||
|
basic root, a change to the existing hierarchy is called for. As it
|
|||
|
stands now, if one wants to catch all exceptions that signal an error
|
|||
|
*and* do not mean the interpreter should be allowed to exit, you must
|
|||
|
specify all but two exceptions specifically in an ``except`` clause.
|
|||
|
That is needlessly explicit. This PEP proposes moving
|
|||
|
KeyboardInterrupt and SystemExit to inherit directly from
|
|||
|
BaseException.
|
|||
|
|
|||
|
Doing this makes catching Exception more reasonable. It would catch
|
|||
|
only exceptions that signify errors. Exceptions that signal that the
|
|||
|
intepreter should exit will not be caught and thus be allowed to
|
|||
|
propagate up and allow the interpreter to terminate.
|
|||
|
|
|||
|
KeyboardInterrupt has been moved since users typically expect an
|
|||
|
application to exit when the press the interrupt key (usually Ctrl-C).
|
|||
|
If people have overly broad ``except`` clauses the expected behaviour
|
|||
|
does not occur.
|
|||
|
|
|||
|
SystemExit has been moved for similar reasons. Since the exception is
|
|||
|
raised when ``sys.exit()`` is called the interpreter should normally
|
|||
|
be allowed to terminate. Unfortunately overly broad ``except``
|
|||
|
clauses can prevent the exit to occur which had been explicitly
|
|||
|
requested.
|
|||
|
|
|||
|
To make sure that people catch Exception most of the time, various
|
|||
|
parts of the documentation and tutorials will need to be updated to
|
|||
|
strongly suggest that Exception be what programmers want to use. Bare
|
|||
|
``except`` clauses or catching BaseException directly should be
|
|||
|
discouraged based on the fact that KeyboardInterrupt and SystemExit
|
|||
|
almost always should be allowed to propagate up.
|
|||
|
|
|||
|
|
|||
|
Transition Plan
|
|||
|
===============
|
|||
|
|
|||
|
Since semantic changes to Python are being proposed, a transition plan
|
|||
|
is needed. The goal is to end up with the new semantics being used in
|
|||
|
Python 3.0 while providing a smooth transition for 2.x code. All
|
|||
|
deprecations mentioned in the plan will lead to the removal of the
|
|||
|
semantics starting in the version following the introduction of the
|
|||
|
deprecation.
|
|||
|
|
|||
|
* Python 2.5
|
|||
|
|
|||
|
- introduce BaseException
|
|||
|
|
|||
|
+ allow exceptions to be new-style classes
|
|||
|
|
|||
|
+ all standard exceptions become new-style classes
|
|||
|
|
|||
|
- Exception, KeyboardInterrupt, and SystemExit inherit from BaseException
|
|||
|
|
|||
|
- deprecate raising string exceptions
|
|||
|
|
|||
|
* Python 2.6
|
|||
|
|
|||
|
- deprecate catching string exceptions
|
|||
|
|
|||
|
* Python 2.7
|
|||
|
|
|||
|
- deprecate raising exceptions that do not inherit from BaseException
|
|||
|
|
|||
|
* Python 2.8
|
|||
|
|
|||
|
- deprecate catching exceptions that do not inherit from BaseException
|
|||
|
|
|||
|
- deprecate ``args`` and ``__getitem__``
|
|||
|
|
|||
|
|
|||
|
References
|
|||
|
==========
|
|||
|
|
|||
|
.. [#pep348] PEP 348 (Exception Reorganization for Python 3.0)
|
|||
|
http://www.python.org/peps/pep-0348.html
|
|||
|
|
|||
|
.. [#hierarchy-good] python-dev Summary for 2004-08-01 through 2004-08-15
|
|||
|
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
|
|||
|
|
|||
|
|
|||
|
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
|
|||
|
End:
|