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 , 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
 PJE has convinced me that I was right in thinking that KeyboardInterrupt was a better fit under ControlFlowExceptions than it was under CriticalError.