Python Language Exceptions: Difference between revisions
(→assert) |
|||
(43 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
=Internal= | =Internal= | ||
* [[Python_Language#Exceptions_.28try.2Fexcept.29|Python Language]] | * [[Python_Language#Exceptions_.28try.2Fexcept.29|Python Language]] | ||
* [[Pytest_Testing_Idioms#Tested_Code_is_Supposed_to_Throw_Exception|Pytest Testing Idioms | Tested Code is Supposed to Throw Exception]] | |||
=TODO= | |||
<font color=darkkhaki> | |||
* PROCESS [[PyOOP]] "Expecting the Unexpected", "Raising exceptions", "Raising an exception", "The effects of an exception", "Handling exceptions", "The exception hierarchy", "Defining our own exceptions", "Case study". | |||
* PROCESS Google Python Style Guide, Exceptions: https://google.github.io/styleguide/pyguide.html#24-exceptions | |||
</font> | |||
=Overview= | =Overview= | ||
<code>[[#try.2Fexcept|try/except]]</code> is a language-level mechanism to handle errors | Exceptions are Python's main error handling mechanism. <code>[[#try.2Fexcept|try/except]]</code> is a language-level mechanism to handle errors that may be caused by a section of the code. Exceptions can be triggered explicitly from the program code with <code>[[#raise|raise]]</code>. A convenient way to conditionally trigger an exception (<code>AssertionError</code>) in the code, use <code>[[#assert|assert]]</code>. | ||
=Exception State= | |||
An exception instance carries an <code>args</code> tuple. | |||
=<tt>try/except</tt>= | =<tt>try/except</tt>= | ||
Line 14: | Line 19: | ||
try: | try: | ||
# do something | # do something | ||
except: | except <SomeException>: | ||
# execute if the previous block caused an error | # execute if the previous block caused an error | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=<tt>finally</tt>= | The code provided under <code>except</code> is referred to as "exception handler". If an exception occurs in a <code>try</code> block and it is not caught in the corresponding <code>except</code> block, it bubbles up until is caught by a matching handler, in the calling layers. If no exception handler is found, Python prints and error message and some information about where the error occurred and then terminates the program. | ||
Note that "bare" <code>except:</code> (the except keyword followed by colon and nothing else) is syntactically valid, but it is considered bad style. A bare <code>except:</code> clause will catch <code>SystemExit</code> and <code>KeyboardInterrupt</code> exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. To catch all exceptions that signal program errors, use <code>except Exception:</code> (bare except is equivalent to <code>except BaseException:</code>). The use of bare <code>except:</code> is limited to two cases: | |||
# If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred. | |||
# If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise. <code>try</code>...<code>finally</code> can be a better way to handle this case. | |||
If more than one type of exception could occur, it is best to provide a separate exception handler for each: | |||
<syntaxhighlight lang='py'> | |||
try: | |||
# do something | |||
except SomeError as ex: | |||
# exception handler for 'SomeError' | |||
except SomeOtherError as ex: | |||
# exception handler for 'SomeOtherError' | |||
finally: | |||
# optional block to execute whether there are exceptions or not | |||
</syntaxhighlight> | |||
<span id='Except_As'></span>The [[Python_Language#Reserved_Words|reserved word <code>as</code>]] is used to store the caught exception into a variable for further introspection. | |||
==Catching Multiple Exceptions on the Same Line== | |||
<syntaxhighlight lang='py'> | |||
try: | |||
# do something | |||
except (UserError, ValidationError) as e: | |||
# ... | |||
</syntaxhighlight> | |||
==<tt>finally</tt>== | |||
The <code>finally</code> block is optional. If specified, is executed regardless of whether there was an exception or not, and after the exception was handled, if there was an exceptions. | |||
=Introspecting Exceptions= | |||
<Font color=darkkhaki>TODO</font> | |||
=<tt>raise</tt>= | =<tt>raise</tt>= | ||
Avoid raising generic <code>Exception</code>s, try to be specific as possible with the exception type and use the most specific exception type that semantically fits the issue. | |||
<syntaxhighlight lang='py'> | |||
raise ValueError('function invoked with no arguments') | |||
</syntaxhighlight> | |||
=<tt> assert </tt>= | =<tt> assert </tt>= | ||
Line 30: | Line 70: | ||
<syntaxhighlight lang='py'> | <syntaxhighlight lang='py'> | ||
assert s is not None, 'The string was supposed to be set!' | assert s is not None, 'The string was supposed to be set!' | ||
</syntaxhighlight> | |||
=Exception Chaining= | |||
Exceptions can be chained, which preserves tracebacks: | |||
<syntaxhighlight lang='py'> | |||
raise RuntimeError('specific message') from error | |||
</syntaxhighlight> | </syntaxhighlight> | ||
=Predefined Exceptions= | =Predefined Exceptions= | ||
{{External|https://docs.python.org/3/library/exceptions.html}} | {{External|https://docs.python.org/3/library/exceptions.html}} | ||
<font size=- | Some exceptions are predefined in the [[Python Language#Python_Standard_Library|Python Standard Library]]. | ||
BaseException | <font size=-2> | ||
BaseException | |||
├─ SystemExit | |||
├─ KeyboardInterrupt | |||
├─ GeneratorExit | |||
└─ Exception | |||
├─ StopIteration | ├─ StopIteration | ||
├─ StopAsyncIteration | ├─ StopAsyncIteration | ||
├─ ArithmeticError | ├─ ArithmeticError | ||
│ | │ ├─ FloatingPointError | ||
│ | │ ├─ OverflowError | ||
│ | │ └─ ZeroDivisionError | ||
├─ AssertionError | |||
├─ <span id='AttributeError'></span>[[Python_Introspection#getattr.28.29|AttributeError]] | |||
├─ BufferError | |||
├─ EOFError | |||
├─ ImportError | |||
│ └─ ModuleNotFoundError | |||
├─ LookupError | |||
│ ├─ IndexError | |||
│ └─ KeyError | |||
├─ MemoryError | |||
├─ NameError | |||
│ └─ UnboundLocalError | |||
├─ OSError | |||
│ ├─ BlockingIOError | |||
│ ├─ ChildProcessError | |||
│ ├─ ConnectionError | |||
│ │ ├─ BrokenPipeError | |||
│ │ ├─ ConnectionAbortedError | |||
│ │ ├─ ConnectionRefusedError | |||
│ │ └─ ConnectionResetError | |||
│ ├─ FileExistsError | |||
| | │ ├─ <span id='FileNotFoundError'></span>[[Python FileNotFoundError|FileNotFoundError]] | ||
│ ├─ InterruptedError | |||
│ ├─ IsADirectoryError | |||
│ ├─ NotADirectoryError | |||
│ ├─ PermissionError | |||
│ ├─ ProcessLookupError | |||
│ ├─ TimeoutError | |||
├─ ReferenceError | |||
├─ RuntimeError | |||
│ ├─ NotImplementedError | |||
│ └─ RecursionError | |||
├─ SyntaxError | |||
│ └─ IndentationError | |||
│ └─ TabError | |||
├─ SystemError | |||
├─ TypeError | |||
├─ <span id='ValueError'></span>[[Python_ValueError#Overview|ValueError]] | |||
│ └─ UnicodeError | |||
│ ├─ UnicodeDecodeError | |||
│ ├─ UnicodeEncodeError | |||
│ └─ UnicodeTranslateError | |||
└─ Warning | |||
├─ DeprecationWarning | |||
├─ PendingDeprecationWarning | |||
├─ RuntimeWarning | |||
├─ SyntaxWarning | |||
├─ UserWarning | |||
├─ FutureWarning | |||
├─ ImportWarning | |||
├─ UnicodeWarning | |||
├─ BytesWarning | |||
├─ EncodingWarning | |||
└─ ResourceWarning | |||
</font> | </font> | ||
==Interesting Exceptions== | |||
===<tt>NotImplementedError</tt>=== | |||
Use <code>NotImplementedError</code>, not <code>NotImplemented</code>, <code>NotImplemented</code> cannot be caught. | |||
=Defining Custom Exceptions= | |||
A custom exception is a class, a child of class <code>Exception</code>. | |||
<syntaxhighlight lang='py'> | |||
class UserError(Exception): | |||
def __init__(self, msg): | |||
super().__init__(msg) | |||
</syntaxhighlight> | |||
=Access Exception State= | |||
Access the message: use <code>str(e)</code>. |
Latest revision as of 20:36, 14 December 2022
Internal
TODO
- PROCESS PyOOP "Expecting the Unexpected", "Raising exceptions", "Raising an exception", "The effects of an exception", "Handling exceptions", "The exception hierarchy", "Defining our own exceptions", "Case study".
- PROCESS Google Python Style Guide, Exceptions: https://google.github.io/styleguide/pyguide.html#24-exceptions
Overview
Exceptions are Python's main error handling mechanism. try/except
is a language-level mechanism to handle errors that may be caused by a section of the code. Exceptions can be triggered explicitly from the program code with raise
. A convenient way to conditionally trigger an exception (AssertionError
) in the code, use assert
.
Exception State
An exception instance carries an args
tuple.
try/except
try/except
is a language-level mechanism to handle errors (traceback) that may be caused by a section of the code. This syntax eliminates tracebacks.
try:
# do something
except <SomeException>:
# execute if the previous block caused an error
The code provided under except
is referred to as "exception handler". If an exception occurs in a try
block and it is not caught in the corresponding except
block, it bubbles up until is caught by a matching handler, in the calling layers. If no exception handler is found, Python prints and error message and some information about where the error occurred and then terminates the program.
Note that "bare" except:
(the except keyword followed by colon and nothing else) is syntactically valid, but it is considered bad style. A bare except:
clause will catch SystemExit
and KeyboardInterrupt
exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. To catch all exceptions that signal program errors, use except Exception:
(bare except is equivalent to except BaseException:
). The use of bare except:
is limited to two cases:
- If the exception handler will be printing out or logging the traceback; at least the user will be aware that an error has occurred.
- If the code needs to do some cleanup work, but then lets the exception propagate upwards with raise.
try
...finally
can be a better way to handle this case.
If more than one type of exception could occur, it is best to provide a separate exception handler for each:
try:
# do something
except SomeError as ex:
# exception handler for 'SomeError'
except SomeOtherError as ex:
# exception handler for 'SomeOtherError'
finally:
# optional block to execute whether there are exceptions or not
The reserved word as
is used to store the caught exception into a variable for further introspection.
Catching Multiple Exceptions on the Same Line
try:
# do something
except (UserError, ValidationError) as e:
# ...
finally
The finally
block is optional. If specified, is executed regardless of whether there was an exception or not, and after the exception was handled, if there was an exceptions.
Introspecting Exceptions
TODO
raise
Avoid raising generic Exception
s, try to be specific as possible with the exception type and use the most specific exception type that semantically fits the issue.
raise ValueError('function invoked with no arguments')
assert
The assert
statement can be used to trigger an AssertionError
conditionally. It can be use with an optional error message, which is becoming part of the exception if the assertion proves false:
assert s is not None
assert s is not None, 'The string was supposed to be set!'
Exception Chaining
Exceptions can be chained, which preserves tracebacks:
raise RuntimeError('specific message') from error
Predefined Exceptions
Some exceptions are predefined in the Python Standard Library.
BaseException ├─ SystemExit ├─ KeyboardInterrupt ├─ GeneratorExit └─ Exception ├─ StopIteration ├─ StopAsyncIteration ├─ ArithmeticError │ ├─ FloatingPointError │ ├─ OverflowError │ └─ ZeroDivisionError ├─ AssertionError ├─ AttributeError ├─ BufferError ├─ EOFError ├─ ImportError │ └─ ModuleNotFoundError ├─ LookupError │ ├─ IndexError │ └─ KeyError ├─ MemoryError ├─ NameError │ └─ UnboundLocalError ├─ OSError │ ├─ BlockingIOError │ ├─ ChildProcessError │ ├─ ConnectionError │ │ ├─ BrokenPipeError │ │ ├─ ConnectionAbortedError │ │ ├─ ConnectionRefusedError │ │ └─ ConnectionResetError │ ├─ FileExistsError │ ├─ FileNotFoundError │ ├─ InterruptedError │ ├─ IsADirectoryError │ ├─ NotADirectoryError │ ├─ PermissionError │ ├─ ProcessLookupError │ ├─ TimeoutError ├─ ReferenceError ├─ RuntimeError │ ├─ NotImplementedError │ └─ RecursionError ├─ SyntaxError │ └─ IndentationError │ └─ TabError ├─ SystemError ├─ TypeError ├─ ValueError │ └─ UnicodeError │ ├─ UnicodeDecodeError │ ├─ UnicodeEncodeError │ └─ UnicodeTranslateError └─ Warning ├─ DeprecationWarning ├─ PendingDeprecationWarning ├─ RuntimeWarning ├─ SyntaxWarning ├─ UserWarning ├─ FutureWarning ├─ ImportWarning ├─ UnicodeWarning ├─ BytesWarning ├─ EncodingWarning └─ ResourceWarning
Interesting Exceptions
NotImplementedError
Use NotImplementedError
, not NotImplemented
, NotImplemented
cannot be caught.
Defining Custom Exceptions
A custom exception is a class, a child of class Exception
.
class UserError(Exception):
def __init__(self, msg):
super().__init__(msg)
Access Exception State
Access the message: use str(e)
.