[Python-Dev] Pre-PEP: Exception Reorganization for Python 3.0

Nick Coghlan ncoghlan at gmail.com
Tue Aug 2 12:00:42 CEST 2005


Stephen J. Turnbull wrote:
> Now, somebody proposed:
> 
> Raisable -+- Exception
>           +- ...
>           +- ControlFlowException -+- StopIteration
>                                    +- KeyboardInterrupt
> 
> As I wrote above, I see no use for that

The use for it is :

   try:
     # do stuff
   except ControlFlowException:
     raise
   except Raisable:
     # handle anything else

Sure, you could write it as:

   try:
     # do stuff
   except (CriticalException, Exception, Warning):
     # handle anything else

But the former structure better reflects the programmers intent (handle 
everything except control flow exceptions).

It's a fact that Python uses exceptions for control flow - KeyboardInterrupt 
[1], StopIteration, SystemExit (and soon to be GeneratorExit as well). 
Grouping them under a common parent allows them to be dealt with as a group, 
rather than their names being spelt out explicitly.

Actually having this in the exception hierarchy is beneficial from a 
pedagogical point of view as well - the hierarchy is practically the first 
thing you encounter when you run "help ('exceptions')" at the interactive prompt.

I have a Python 2.5 candidate hierarchy below, which uses dual inheritance to 
avoid breaking backward compatibility - any existing except clauses will catch 
all of the exceptions they used to catch. The only new inheritance introduced 
is to new exceptions, also avoiding backward compatibility problems, as any 
existing except clauses will let by all of the exceptions they used to let by. 
There are no removals, but the deprecation process is started in order to 
change the names of ReferenceError and RuntimeWarning to WeakReferenceError 
and SemanticsWarning.

With this hierarchy, the recommended parent class for application errors 
becomes Error, and "except Error:" is preferred to any of "except:", "except 
Exception:" and "except StandardError:" (although these three continue to 
catch everything they used to catch).

The recommended workaround for libraries raising errors which still inherit 
directly from Exception is:
   try:
     # Use library
   except (ControlFlowException, CriticalError):
     raise
   except Exception:
     # Do stuff

(Remove the 'Exception' part if the library is so outdated that it still 
raises string exceptions)

Applications which use exceptions to control the flow of execution rather than 
to indicate an error (e.g. breaking out of multiple nested loops) are free to 
use ControlFlowException directly, or else define their own subclasses of 
ControlFlowException.

This hierarchy achieves my main goal for the exception reorganisation, which 
is to make it easy for scripts and applications to avoid inadvertently 
swallowing the control flow exceptions and critical errors, while still being 
able to provide generic error handlers for application faults. (Hmm, the 
pre-PEP doesn't include that as a goal in the 'Philosophy' section. . .)

Python 2.4 Compatible Improved Exception Hierarchy v 0.1
========================================================

Exception
+-- ControlFlowException (new)
      +-- GeneratorExit (new)
      +-- StopIteration
      +-- SystemExit
      +-- KeyboardInterrupt (dual-inheritance new)
+-- StandardError
      +-- KeyboardInterrupt (dual-inheritance new)
      +-- CriticalError (new)
          +-- MemoryError
          +-- SystemError
      +-- Error (new)
          +-- AssertionError
          +-- AttributeError
          +-- EOFError
          +-- ImportError
          +-- TypeError
          +-- ReferenceError (deprecated), WeakReferenceError (new alias)
          +-- ArithmeticError
              +-- FloatingPointError
              +-- DivideByZeroError
              +-- OverflowError
          +-- EnvironmentError
              +-- OSError
                  +-- WindowsError
              +-- IOError
          +-- LookupError
              +-- IndexError
              +-- KeyError
          +-- NameError
              +-- UnboundLocalError
          +-- RuntimeError
              +-- NotImplementedError
          +-- SyntaxError
              +-- IndentationError
                  +-- TabError
          +-- ValueError
              +-- UnicodeError
                  +-- UnicodeDecodeError
                  +-- UnicodeEncodeError
                  +-- UnicodeTranslateError
+-- Warning
      +-- DeprecationWarning
      +-- FutureWarning
      +-- PendingDeprecationWarning
      +-- RuntimeWarning (deprecated), SemanticsWarning (new alias)
      +-- SyntaxWarning
      +-- UserWarning

Cheers,
Nick.

[1] PJE has convinced me that I was right in thinking that KeyboardInterrupt 
was a better fit under ControlFlowExceptions than it was under CriticalError.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://boredomandlaziness.blogspot.com


More information about the Python-Dev mailing list