Movatterモバイル変換


[0]ホーム

URL:


Following system colour schemeSelected dark colour schemeSelected light colour scheme

Python Enhancement Proposals

PEP 352 – Required Superclass for Exceptions

Author:
Brett Cannon, Guido van Rossum
Status:
Final
Type:
Standards Track
Created:
27-Oct-2005
Python-Version:
2.5
Post-History:


Table of Contents

Abstract

In Python 2.4 and before, any (classic) class can be raised as anexception. The plan for 2.5 was to allow new-style classes, but thismakes the problem worse – it would meanany class (orinstance) can be raised! This is a problem as it prevents anyguarantees from being made about the interface of exceptions.This PEP proposes introducing a new superclass that all raised objectsmust inherit from. Imposing the restriction will allow a standardinterface for exceptions to exist that can be relied upon. It alsoleads to a known hierarchy for all exceptions to adhere to.

One might counter that requiring a specific base class for aparticular interface is unPythonic. However, in the specific case ofexceptions there’s a good reason (which has generally been agreed toon python-dev): requiring hierarchy helps code that wants tocatchexceptions by making it possible to catchall exceptions explicitlyby writingexceptBaseException: instead ofexcept*:.[1]

Introducing a new superclass for exceptions also gives us the chanceto rearrange the exception hierarchy slightly for the better. As itcurrently stands, all exceptions in the built-in namespace inheritfrom Exception. This is a problem since this includes two exceptions(KeyboardInterrupt and SystemExit) that often need to be excepted fromthe application’s exception handling: the default behavior of shuttingthe interpreter down without a traceback is usually more desirable thanwhatever the application might do (with the possible exception ofapplications that emulate Python’s interactive command loop with>>> prompt). Changing it so that these two exceptions inheritfrom the common superclass instead of Exception will make it easy forpeople to writeexcept clauses that are not overreaching and notcatch exceptions that should propagate up.

This PEP is based on previous work done forPEP 348.

Requiring a Common Superclass

This PEP proposes introducing a new exception named BaseException thatis a new-style class and has a single attribute,args. Belowis the code as the exception will work in Python 3.0 (how it willwork in Python 2.x is covered in theTransition Plan section):

classBaseException(object):"""Superclass representing the base of the exception hierarchy.    Provides an 'args' attribute that contains all arguments passed    to the constructor.  Suggested practice, though, is that only a    single string argument be passed to the constructor.    """def__init__(self,*args):self.args=argsdef__str__(self):iflen(self.args)==1:returnstr(self.args[0])else:returnstr(self.args)def__repr__(self):return"%s(*%s)"%(self.__class__.__name__,repr(self.args))

No restriction is placed upon what may be passed in forargsfor backwards-compatibility reasons. In practice, though, onlya single string argument should be used. This keeps the stringrepresentation of the exception to be a useful message about theexception that is human-readable; this is why the__str__ methodspecial-cases on length-1args value. Including programmaticinformation (e.g., an error code number) should be stored as aseparate attribute in a subclass.

Theraise statement will be changed to require that any objectpassed to it must inherit from BaseException. This will make surethat all exceptions fall within a single hierarchy that is anchored atBaseException[1]. This also guarantees a basicinterface that is inherited from BaseException. The change toraise will be enforced starting in Python 3.0 (see theTransitionPlan 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 abasic root, a change to the existing hierarchy is called for. As itstands now, if one wants to catch all exceptions that signal an errorand do not mean the interpreter should be allowed to exit, you mustspecify all but two exceptions specifically in anexcept clauseor catch the two exceptions separately and then re-raise them andhave all other exceptions fall through to a bareexcept clause:

except(KeyboardInterrupt,SystemExit):raiseexcept:...

That is needlessly explicit. This PEP proposes movingKeyboardInterrupt and SystemExit to inherit directly fromBaseException.

-BaseException|-KeyboardInterrupt|-SystemExit|-Exception|-(allothercurrentbuilt-inexceptions)

Doing this makes catching Exception more reasonable. It would catchonly exceptions that signify errors. Exceptions that signal that theinterpreter should exit will not be caught and thus be allowed topropagate up and allow the interpreter to terminate.

KeyboardInterrupt has been moved since users typically expect anapplication to exit when they press the interrupt key (usually Ctrl-C).If people have overly broadexcept clauses the expected behaviourdoes not occur.

SystemExit has been moved for similar reasons. Since the exception israised whensys.exit() is called the interpreter should normallybe allowed to terminate. Unfortunately overly broadexceptclauses can prevent the explicitly requested exit from occurring.

To make sure that people catch Exception most of the time, variousparts of the documentation and tutorials will need to be updated tostrongly suggest that Exception be what programmers want to use. Bareexcept clauses or catching BaseException directly should bediscouraged based on the fact that KeyboardInterrupt and SystemExitalmost always should be allowed to propagate up.

Transition Plan

Since semantic changes to Python are being proposed, a transition planis needed. The goal is to end up with the new semantics being used inPython 3.0 while providing a smooth transition for 2.x code. Alldeprecations mentioned in the plan will lead to the removal of thesemantics starting in the version following the initial deprecation.

Here is BaseException as implemented in the 2.x series:

classBaseException(object):"""Superclass representing the base of the exception hierarchy.    The __getitem__ method is provided for backwards-compatibility    and will be deprecated at some point.  The 'message' attribute    is also deprecated.    """def__init__(self,*args):self.args=argsdef__str__(self):returnstr(self.args[0]iflen(self.args)<=1elseself.args)def__repr__(self):func_args=repr(self.args)ifself.argselse"()"returnself.__class__.__name__+func_argsdef__getitem__(self,index):"""Index into arguments passed in during instantiation.        Provided for backwards-compatibility and will be        deprecated.        """returnself.args[index]def_get_message(self):"""Method for 'message' property."""warnings.warn("the 'message' attribute has been deprecated ""since Python 2.6")returnself.args[0]iflen(args)==1else''message=property(_get_message,doc="access the 'message' attribute; ""deprecated and provided only for ""backwards-compatibility")

Deprecation of features in Python 2.9 is optional. This is because itis not known at this time if Python 2.9 (which is slated to be thelast version in the 2.x series) will actively deprecate features thatwill not be in 3.0. It is conceivable that no deprecation warningswill be used in 2.9 since there could be such a difference between 2.9and 3.0 that it would make 2.9 too “noisy” in terms of warnings. Thusthe proposed deprecation warnings for Python 2.9 will be revisitedwhen development of that version begins, to determine if they are stilldesired.

  • Python 2.5 [done]
    • all standard exceptions become new-style classes [done]
    • introduce BaseException [done]
    • Exception, KeyboardInterrupt, and SystemExit inherit fromBaseException [done]
    • deprecate raising string exceptions [done]
  • Python 2.6 [done]
    • deprecate catching string exceptions [done]
    • deprecatemessage attribute (seeRetracted Ideas) [done]
  • Python 2.7 [done]
    • deprecate raising exceptions that do not inherit from BaseException
  • Python 3.0 [done]
    • drop everything that was deprecated above:
      • string exceptions (both raising and catching) [done]
      • all exceptions must inherit from BaseException [done]
      • drop__getitem__,message [done]

Retracted Ideas

A previous version of this PEP that was implemented in Python 2.5included a ‘message’ attribute on BaseException. Its purpose was tobegin a transition to BaseException accepting only a single argument.This was to tighten the interface and to force people to useattributes in subclasses to carry arbitrary information with anexception instead of cramming it all intoargs.

Unfortunately, while implementing the removal of theargsattribute in Python 3.0 at the PyCon 2007 sprint[2], it was discovered that the transition wasvery painful, especially for C extension modules. It was decided thatit would be better to deprecate themessage attribute inPython 2.6 (and remove it in Python 2.7 and Python 3.0) and consider amore long-term transition strategy in Python 3.0 to removemultiple-argument support in BaseException in preference of acceptingonly a single argument. Thus the introduction ofmessage and theoriginal deprecation ofargs has been retracted.

References

[1] (1,2)
python-dev Summary for 2004-08-01 through 2004-08-15http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception
[2]
python-3000 email (“How far to go with cleaning up exceptions”)https://mail.python.org/pipermail/python-3000/2007-March/005911.html

Copyright

This document has been placed in the public domain.


Source:https://github.com/python/peps/blob/main/peps/pep-0352.rst

Last modified:2024-12-03 18:09:24 GMT


[8]ページ先頭

©2009-2025 Movatter.jp