Nov 1, 2017 10:10:27 PM |
The Python Exception Class Hierarchy
An overview of the Python exception class hierarchy, including a quick look at all the top-level exception classes in the standard library.
The Python exception class hierarchy consists of a few dozen different exceptions spread across a handful of important base class types. As with most programming languages, errors occur within a Python application when something unexpected goes wrong. Anything from improper arithmetic and running out of memory to invalid file references and unicode formatting errors may be raised by Python under certain circumstances.
Most of the errors we’ll explore in this series are considered exceptions
, which indicate that these are non-fatal
errors. While a fatal
error will halt execution of the current application, all non-fatal exceptions allow execution to continue. This allows our code to explicitly catch or rescue
the raised exception and programmatically react to it in an appropriate manner.
Let’s start by looking at the full Python exception class hierarchy, as seen below:
- BaseException
- Exception
- 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
- StopIteration
- StopAsyncIteration
- SyntaxError
- IndentationError
- TabError
- IndentationError
- SystemError
- TypeError
- ValueError
- UnicodeError
- UnicodeDecodeError
- UnicodeEncodeError
- UnicodeTranslateError
- UnicodeError
- Warning
- BytesWarning
- DeprecationWarning
- FutureWarning
- ImportWarning
- PendingDeprecationWarning
- ResourceWarning
- RuntimeWarning
- SyntaxWarning
- UnicodeWarning
- UserWarning
- ArithmeticError
- GeneratorExit
- KeyboardInterrupt
- SystemExit
- Exception
As we publish future exception-specific articles in this series we’ll update the full list above to relevant tutorial and article links for each exception, so this post can act as a go-to resource for Python exception handling tips.
Major Exception Types Overview
Next, let’s briefly discuss each important top-level exception type. These top-level exceptions will serve as a basis for digging into specific exceptions in future articles. Before we do that, however, it’s worth pointing out what might appear as a slight discrepancy when looking over the list of exception classes provided in Python. To illustrate, look closely at this small snippet of the Python exception class hierarchy and see if anything slightly strange pops out to you:
- BaseException
- Exception
- ArithmeticError
- FloatingPointError
- OverflowError
- ZeroDivisionError
- AssertionError
- ArithmeticError
- Exception
For developers that have worked with other programming languages in the past, what you might take note of is the distinction between using the word exception
in the BaseException
and Exception
parent classes, and the use of error
in most subclasses therein. Most other languages, such as .NET or Java, explicitly differentiate between exceptions
and errors
by separating them into distinct categories. In such languages, errors
typically denote fatal
errors (those that crash the application), whereas exceptions
are catchable/rescuable errors.
Yet, as we see in the hierarchy above, Python merely inherits from Exception
with a series of XYZError
classes. The reason for this naming convention comes from the PEP8
Python style guide, which makes an explicit mention that «you should use the suffix ‘Error’ on your exception names (if the exception is actually an error).» I’ve added the extra emphasis to that quote, because the latter point is critical here — most Python exceptions with Error
in the name are, in fact, errors.
BaseException
The BaseException
class is, as the name suggests, the base class for all built-in exceptions in Python. Typically, this exception is never raised on its own, and should instead be inherited by other, lesser exception classes that can be raised.
The BaseException
class (and, thus, all subclass exceptions as well) allows a tuple
of arguments to be passed when creating a new instance of the class. In most cases, a single argument will be passed to an exception, which is a string value indicating the specific error message.
This class also includes a with_traceback(tb)
method, which explicitly sets the new traceback information to the tb
argument that was passed to it.
Exception
Exception
is the most commonly-inherited exception type (outside of the true base class of BaseException
). In addition, all exception classes that are considered errors are subclasses of the Exception
class. In general, any custom exception class you create in your own code should inherit from Exception
.
The Exception
class contains many direct child subclasses that handle most Python errors, so we’ll briefly go over each below:
ArithmeticError
— The base class for the variety of arithmetic errors, such as when attempting to divide by zero, or when an arithmetic result would be too large for Python to accurately represent.AssertionError
— This error is raised when a call to the [assert
] statement fails.AttributeError
— Python’s syntax includes something calledattribute references
, which is just the Python way of describing what you might know of asdot notation
. In essence, anyprimary token
in Python (like anidentifier
,literal
, and so forth) can be written and followed by a period (.
), which is then followed by anidentifier
. That syntax (i.e.primary.identifier
) is called anattribute reference
, and anytime the executing script encounters an error in such syntax anAttributeError
is raised.BufferError
— Python allows applications to access low level memory streams in the form of abuffer
. For example, thebytes
class can be used to directly work with bytes of information via a memory buffer. When something goes wrong within such a buffer operation aBufferError
is raised.EOFError
— Similar to the Java EOFException article we did a few days ago, Python’sEOFError
is raised when using theinput()
function and reaching the end of a file without any data.ImportError
— Modules are usually loaded in memory for Python scripts to use via theimport
statement (e.g.import car from vehicles
). However, if animport
attempt fails anImportError
will often be raised.LookupError
— LikeArithmeticError
, theLookupError
is generally considered a base class from which other subclasses should inherit. AllLookupError
subclasses deal with improper calls to a collection are made by using invalidkey
orindex
values.MemoryError
— In the event that your Python application is about to run out of memory aMemoryError
will be raised. Since Python is smart enough to detect this potential issue slightly before all memory is used up, aMemoryError
can berescued
and allow you to recover from the situation by performing garbage collection of some kind.NameError
— Raised when trying to use anidentifier
with an invalid or unknown name.OSError
— This error is raised when a system-level problem occurs, such as failing to find a local file on disk or running out of disk space entirely.OSError
is a parent class to many subclasses explicitly used for certain issues related to operating system failure, so we’ll explore those in future publications.ReferenceError
— Python includes the weakref module, which allows Python code to create a specific type of reference known as aweak reference
. Aweak reference
is a reference that is not «strong» enough to keep the referenced object alive. This means that the next cycle of garbage collection will identify the weakly referenced object as no longer strongly referenced by another object, causing the weakly referenced object to be destroyed to free up resources. If aweak reference
proxy created via theweakref.proxy()
function is used after the object that is referenced has already been destroyed via garbage collection, aReferenceError
will be raised.RuntimeError
— ARuntimeError
is typically used as a catchall for when an error occurs that doesn’t really fit into any other specific error classification.StopIteration
— If nodefault
value is passed to thenext()
function when iterating over a collection, and that collection has no more iterated value to retrieve, aStopIteration
exception is raised. Note that this is not classified as anError
, since it doesn’t mean that an error has occurred.StopAsyncIteration
— As of version 3.5, Python now includes coroutines for asynchronous transactions using theasync
andawait
syntax. As part of this feature, collections can be asynchronously iterated using the__anext__()
method. The__anext__()
method requires that aStopAsyncIteration
instance be raised in order to halt async iteration.SyntaxError
— Just like most programming languages, aSyntaxError
in Python indicates that there is some improper syntax somewhere in your script file. ASyntaxError
can be raised directly from an executing script, or produced via functions likeeval()
andexec()
.SystemError
— A generic error that is raised when something goes wrong with the Python interpreter (not to be confused with theOSError
, which handles operating system issues).TypeError
— This error is raised when attempting to perform an operation on an incorrect object type.ValueError
— Should be raised when a function or method receives an argument of the correct type, but with an actual value that is invalid for some reason.Warning
— Another parent class to many subclasses, theWarning
class is used to alert the user in non-dire situations. There are a number of subclass warnings that we’ll explore in future articles.
GeneratorExit
A generator
is a specific type of iterator in Python, which simplifies the process of creating iterators with constantly changing values. By using the yield
statement within a generator code block, Python will return or «generate» a new value for each call to next()
. When the explicit generator.close()
method is called a GeneratorExit
instance is raised.
KeyboardInterrupt
This simple exception is raised when the user presses a key combination that causes an interrupt
to the executing script. For example, many terminals accept Ctrl+C
as an interrupt keystroke.
SystemExit
Finally, the SystemExit
exception is raised when calling the sys.exit()
method, which explicitly closes down the executing script and exits Python. Since this is an exception, it can be rescued
and programmatically responded to immediately before the script actually shuts down.
That’s just a small taste of the powerful, built-in Python exception class hierarchy as of version 3.6. Stay tuned for more in-depth articles examining each of these exceptions in greater detail, and be sure to check out Airbrake’s robust error monitoring software, which provides real-time error monitoring and automatic exception reporting for all your development projects. Airbrake’s state of the art web dashboard ensures you receive round-the-clock status updates on your application’s health and error rates. No matter what you’re working on, Airbrake easily integrates with all the most popular languages and frameworks. Plus, Airbrake makes it easy to customize exception parameters, while giving you complete control of the active error filter system, so you only gather the errors that matter most.
Check out Airbrake’s error monitoring software today with a 14-day trial and see for yourself why so many of the world’s best engineering teams use Airbrake to revolutionize their exception handling practices!
Description¶
In the past, Python has supported simple string messages as exceptions as well as classes. Since 1.5, all of the standard library modules use classes for exceptions. Starting with Python 2.5, string exceptions result in a DeprecationWarning, and support for string exceptions will be removed in the future.
Base Classes¶
The exception classes are defined in a hierarchy, described in the standard library documentation. In addition to the obvious organizational benefits, exception inheritance is useful because related exceptions can be caught by catching their base class. In most cases, these base classes are not intended to be raised directly.
BaseException¶
Base class for all exceptions. Implements logic for creating a string
representation of the exception using str() from the arguments passed
to the constructor.
Exception¶
Base class for exceptions that do not result in quitting the running application.
All user-defined exceptions should use Exception as a base class.
StandardError¶
Base class for built-in exceptions used in the standard library.
ArithmeticError¶
Base class for math-related errors.
LookupError¶
Base class for errors raised when something can’t be found.
EnvironmentError¶
Base class for errors that come from outside of Python (the operating
system, filesystem, etc.).
Raised Exceptions¶
AssertionError¶
An AssertionError is raised by a failed assert statement.
assert False, 'The assertion failed'
$ python exceptions_AssertionError_assert.py Traceback (most recent call last): File "exceptions_AssertionError_assert.py", line 12, in <module> assert False, 'The assertion failed' AssertionError: The assertion failed
It is also used in the unittest module in methods like failIf().
import unittest class AssertionExample(unittest.TestCase): def test(self): self.failUnless(False) unittest.main()
$ python exceptions_AssertionError_unittest.py F ====================================================================== FAIL: test (__main__.AssertionExample) ---------------------------------------------------------------------- Traceback (most recent call last): File "exceptions_AssertionError_unittest.py", line 17, in test self.failUnless(False) AssertionError: False is not true ---------------------------------------------------------------------- Ran 1 test in 0.000s FAILED (failures=1)
AttributeError¶
When an attribute reference or assignment fails, AttributeError is
raised. For example, when trying to reference an attribute that does
not exist:
class NoAttributes(object): pass o = NoAttributes() print o.attribute
$ python exceptions_AttributeError.py Traceback (most recent call last): File "exceptions_AttributeError.py", line 16, in <module> print o.attribute AttributeError: 'NoAttributes' object has no attribute 'attribute'
Or when trying to modify a read-only attribute:
class MyClass(object): @property def attribute(self): return 'This is the attribute value' o = MyClass() print o.attribute o.attribute = 'New value'
$ python exceptions_AttributeError_assignment.py This is the attribute value Traceback (most recent call last): File "exceptions_AttributeError_assignment.py", line 20, in <module> o.attribute = 'New value' AttributeError: can't set attribute
EOFError¶
An EOFError is raised when a built-in function like input() or
raw_input() do not read any data before encountering the end of
their input stream. The file methods like read() return an empty
string at the end of the file.
while True: data = raw_input('prompt:') print 'READ:', data
$ echo hello | python PyMOTW/exceptions/exceptions_EOFError.py prompt:READ: hello prompt:Traceback (most recent call last): File "PyMOTW/exceptions/exceptions_EOFError.py", line 13, in <module> data = raw_input('prompt:') EOFError: EOF when reading a line
FloatingPointError¶
Raised by floating point operations that result in errors, when
floating point exception control (fpectl) is turned on. Enabling
fpectl requires an interpreter compiled with the
—with-fpectl flag. Using fpectl is discouraged in the
stdlib docs.
import math import fpectl print 'Control off:', math.exp(1000) fpectl.turnon_sigfpe() print 'Control on:', math.exp(1000)
GeneratorExit¶
Raised inside a generator the generator’s close() method is called.
def my_generator(): try: for i in range(5): print 'Yielding', i yield i except GeneratorExit: print 'Exiting early' g = my_generator() print g.next() g.close()
$ python exceptions_GeneratorExit.py Yielding 0 0 Exiting early
IOError¶
Raised when input or output fails, for example if a disk fills up or
an input file does not exist.
f = open('/does/not/exist', 'r')
$ python exceptions_IOError.py Traceback (most recent call last): File "exceptions_IOError.py", line 12, in <module> f = open('/does/not/exist', 'r') IOError: [Errno 2] No such file or directory: '/does/not/exist'
ImportError¶
Raised when a module, or member of a module, cannot be imported.
There are a few conditions where an ImportError might be raised.
- If a module does not exist.
import module_does_not_exist
$ python exceptions_ImportError_nomodule.py Traceback (most recent call last): File "exceptions_ImportError_nomodule.py", line 12, in <module> import module_does_not_exist ImportError: No module named module_does_not_exist
2. If from X import Y is used and Y cannot be found inside the
module X, an ImportError is raised.
from exceptions import MadeUpName
$ python exceptions_ImportError_missingname.py Traceback (most recent call last): File "exceptions_ImportError_missingname.py", line 12, in <module> from exceptions import MadeUpName ImportError: cannot import name MadeUpName
IndexError¶
An IndexError is raised when a sequence reference is out of range.
my_seq = [ 0, 1, 2 ] print my_seq[3]
$ python exceptions_IndexError.py Traceback (most recent call last): File "exceptions_IndexError.py", line 13, in <module> print my_seq[3] IndexError: list index out of range
KeyError¶
Similarly, a KeyError is raised when a value is not found as a key of a dictionary.
d = { 'a':1, 'b':2 } print d['c']
$ python exceptions_KeyError.py Traceback (most recent call last): File "exceptions_KeyError.py", line 13, in <module> print d['c'] KeyError: 'c'
KeyboardInterrupt¶
A KeyboardInterrupt occurs whenever the user presses Ctrl-C (or
Delete) to stop a running program. Unlike most of the other
exceptions, KeyboardInterrupt inherits directly from BaseException to
avoid being caught by global exception handlers that catch Exception.
try: print 'Press Return or Ctrl-C:', ignored = raw_input() except Exception, err: print 'Caught exception:', err except KeyboardInterrupt, err: print 'Caught KeyboardInterrupt' else: print 'No exception'
Pressing Ctrl-C at the prompt causes a KeyboardInterrupt exception.
$ python exceptions_KeyboardInterrupt.py Press Return or Ctrl-C: ^CCaught KeyboardInterrupt
MemoryError¶
If your program runs out of memory and it is possible to recover (by
deleting some objects, for example), a MemoryError is raised.
import itertools # Try to create a MemoryError by allocating a lot of memory l = [] for i in range(3): try: for j in itertools.count(1): print i, j l.append('*' * (2**30)) except MemoryError: print '(error, discarding existing list)' l = []
$ python exceptions_MemoryError.py python(49670) malloc: *** mmap(size=1073745920) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug python(49670) malloc: *** mmap(size=1073745920) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug python(49670) malloc: *** mmap(size=1073745920) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug 0 1 0 2 0 3 (error, discarding existing list) 1 1 1 2 1 3 (error, discarding existing list) 2 1 2 2 2 3 (error, discarding existing list)
NameError¶
NameErrors are raised when your code refers to a name that does not
exist in the current scope. For example, an unqualified variable
name.
def func(): print unknown_name func()
$ python exceptions_NameError.py Traceback (most recent call last): File "exceptions_NameError.py", line 15, in <module> func() File "exceptions_NameError.py", line 13, in func print unknown_name NameError: global name 'unknown_name' is not defined
NotImplementedError¶
User-defined base classes can raise NotImplementedError to indicate
that a method or behavior needs to be defined by a subclass,
simulating an interface.
class BaseClass(object): """Defines the interface""" def __init__(self): super(BaseClass, self).__init__() def do_something(self): """The interface, not implemented""" raise NotImplementedError(self.__class__.__name__ + '.do_something') class SubClass(BaseClass): """Implementes the interface""" def do_something(self): """really does something""" print self.__class__.__name__ + ' doing something!' SubClass().do_something() BaseClass().do_something()
$ python exceptions_NotImplementedError.py SubClass doing something! Traceback (most recent call last): File "exceptions_NotImplementedError.py", line 27, in <module> BaseClass().do_something() File "exceptions_NotImplementedError.py", line 18, in do_something raise NotImplementedError(self.__class__.__name__ + '.do_something') NotImplementedError: BaseClass.do_something
See also
abc — Abstract base classes
OSError¶
OSError serves as the error class for the os module, and is
raised when an error comes back from an os-specific function.
import os for i in range(10): print i, os.ttyname(i)
$ python exceptions_OSError.py 0 /dev/ttys000 1 Traceback (most recent call last): File "exceptions_OSError.py", line 15, in <module> print i, os.ttyname(i) OSError: [Errno 25] Inappropriate ioctl for device
OverflowError¶
When an arithmetic operation exceeds the limits of the variable type,
an OverflowError is raise. Long integers allocate more space as
values grow, so they end up raising MemoryError. Floating point
exception handling is not standardized, so floats are not checked.
Regular integers are converted to long values as needed.
import sys print 'Regular integer: (maxint=%s)' % sys.maxint try: i = sys.maxint * 3 print 'No overflow for ', type(i), 'i =', i except OverflowError, err: print 'Overflowed at ', i, err print print 'Long integer:' for i in range(0, 100, 10): print '%2d' % i, 2L ** i print print 'Floating point values:' try: f = 2.0**i for i in range(100): print i, f f = f ** 2 except OverflowError, err: print 'Overflowed after ', f, err
$ python exceptions_OverflowError.py Regular integer: (maxint=9223372036854775807) No overflow for <type 'long'> i = 27670116110564327421 Long integer: 0 1 10 1024 20 1048576 30 1073741824 40 1099511627776 50 1125899906842624 60 1152921504606846976 70 1180591620717411303424 80 1208925819614629174706176 90 1237940039285380274899124224 Floating point values: 0 1.23794003929e+27 1 1.53249554087e+54 2 2.34854258277e+108 3 5.5156522631e+216 Overflowed after 5.5156522631e+216 (34, 'Result too large')
ReferenceError¶
When a weakref proxy is used to access an object that has
already been garbage collected, a ReferenceError occurs.
import gc import weakref class ExpensiveObject(object): def __init__(self, name): self.name = name def __del__(self): print '(Deleting %s)' % self obj = ExpensiveObject('obj') p = weakref.proxy(obj) print 'BEFORE:', p.name obj = None print 'AFTER:', p.name
$ python exceptions_ReferenceError.py BEFORE: obj (Deleting <__main__.ExpensiveObject object at 0x10046e4d0>) AFTER: Traceback (most recent call last): File "exceptions_ReferenceError.py", line 26, in <module> print 'AFTER:', p.name ReferenceError: weakly-referenced object no longer exists
RuntimeError¶
A RuntimeError exception is used when no other more specific exception
applies. The interpreter does not raise this exception itself very
often, but some user code does.
StopIteration¶
When an iterator is done, it’s next() method raises StopIteration.
This exception is not considered an error.
l=[0,1,2] i=iter(l) print i print i.next() print i.next() print i.next() print i.next()
$ python exceptions_StopIteration.py <listiterator object at 0x10045f650> 0 1 2 Traceback (most recent call last): File "exceptions_StopIteration.py", line 19, in <module> print i.next() StopIteration
SyntaxError¶
A SyntaxError occurs any time the parser finds source code it does not
understand. This can be while importing a module, invoking exec,
or calling eval(). Attributes of the exception can be used to
find exactly what part of the input text caused the exception.
try: print eval('five times three') except SyntaxError, err: print 'Syntax error %s (%s-%s): %s' % (err.filename, err.lineno, err.offset, err.text) print err
$ python exceptions_SyntaxError.py Syntax error <string> (1-10): five times three invalid syntax (<string>, line 1)
SystemError¶
When an error occurs in the interpreter itself and there is some
chance of continuing to run successfully, it raises a SystemError.
SystemErrors probably indicate a bug in the interpreter and should be
reported to the maintainer.
SystemExit¶
When sys.exit() is called, it raises SystemExit instead of exiting
immediately. This allows cleanup code in try:finally blocks to
run and special environments (like debuggers and test frameworks) to
catch the exception and avoid exiting.
TypeError¶
TypeErrors are caused by combining the wrong type of objects, or
calling a function with the wrong type of object.
result = ('tuple',) + 'string'
$ python exceptions_TypeError.py Traceback (most recent call last): File "exceptions_TypeError.py", line 12, in <module> result = ('tuple',) + 'string' TypeError: can only concatenate tuple (not "str") to tuple
UnboundLocalError¶
An UnboundLocalError is a type of NameError specific to local variable
names.
def throws_global_name_error(): print unknown_global_name def throws_unbound_local(): local_val = local_val + 1 print local_val try: throws_global_name_error() except NameError, err: print 'Global name error:', err try: throws_unbound_local() except UnboundLocalError, err: print 'Local name error:', err
The difference between the global NameError and the UnboundLocal is
the way the name is used. Because the name “local_val” appears on the
left side of an expression, it is interpreted as a local variable
name.
$ python exceptions_UnboundLocalError.py Global name error: global name 'unknown_global_name' is not defined Local name error: local variable 'local_val' referenced before assignment
UnicodeError¶
UnicodeError is a subclass of ValueError and is
raised when a Unicode problem occurs. There are separate subclasses
for UnicodeEncodeError, UnicodeDecodeError, and
UnicodeTranslateError.
ValueError¶
A ValueError is used when a function receives a value that has the
right type but an invalid value.
$ python exceptions_ValueError.py Traceback (most recent call last): File "exceptions_ValueError.py", line 12, in <module> print chr(1024) ValueError: chr() arg not in range(256)
ZeroDivisionError¶
When zero shows up in the denominator of a division operation, a
ZeroDivisionError is raised.
$ python exceptions_ZeroDivisionError.py Traceback (most recent call last): File "exceptions_ZeroDivisionError.py", line 12, in <module> print 1/0 ZeroDivisionError: integer division or modulo by zero
Warning Categories¶
There are also several exceptions defined for use with the warnings module.
- Warning
- The base class for all warnings.
- UserWarning
- Base class for warnings coming from user code.
- DeprecationWarning
- Used for features no longer being maintained.
- PendingDeprecationWarning
- Used for features that are soon going to be deprecated.
- SyntaxWarning
- Used for questionable syntax.
- RuntimeWarning
- Used for events that happen at runtime that might cause problems.
- FutureWarning
- Warning about changes to the language or library that are coming at a later time.
- ImportWarning
- Warn about problems importing a module.
- UnicodeWarning
- Warn about problems with unicode text.
See also
- exceptions
- The standard library documentation for this module.
- warnings
- Non-error warning messages.
Содержание:
- Базовый класс для встроенных исключений
BaseException
, - Базовый класс пользовательских исключений
Exception
, - Базовый класс арифметических исключений
ArithmeticError
, - Базовый класс исключений связанных с буфером
BufferError
, - Базовый класс исключений связанных с индексированием
LookupError
,
BaseException
:
Базовый класс для всех встроенных исключений. Он не предназначен для прямого наследования определяемыми пользователем классами, для этого используйте исключение Exception
. Если функция str()
вызывается на экземпляре этого класса, то возвращается представление аргумента(ов) к экземпляру или пустая строка, когда аргументов не было.
Атрибуты и методы BaseException
:
BaseException.args
:
Атрибут BaseException.args
представляет собой кортеж аргументов, заданных конструктору исключений. Некоторые встроенные исключения (например, OSError) ожидают определенного числа аргументов и присваивают особое значение элементам этого кортежа, в то время как другие обычно вызываются только с одной строкой, дающей сообщение об ошибке.
BaseException.with_traceback(tb)
:
Метод BaseException.with_traceback(tb)
устанавливает аргумент tb
в качестве новой обратной трассировки для исключения и возвращает объект исключения. Он обычно используется в коде обработки исключений, как это:
try: ... except SomeException: tb = sys.exc_info()[2] raise OtherException(...).with_traceback(tb)
BaseException.add_note(note)
:
Метод BaseException.add_note()
добавляет строку примечания к примечаниям исключения, которые появляются в стандартной трассировке после строки исключения. Ошибка TypeError
возникает, если аргумент note
не является строкой.
Добавлен в Python 3.11.
BaseException.__notes__
:
Атрибут BaseException.__notes__
— это список заметок этого исключения, которые были добавлены с помощью BaseException.add_note()
. Этот атрибут создается при вызове метода BaseException.add_note()
.
Добавлен в Python 3.11.
Exception
:
ArithmeticError
:
Исключение ArithmeticError
это базовый класс для трех встроенных исключений, которые поднимаются для различных арифметических ошибок:
OverflowError
,ZeroDivisionError
,FloatingPointError
.
BufferError
:
Исключение BufferError
поднимается, когда операция, связанная с буфером, не может быть выполнена.
LookupError
:
Исключение LookupError
это базовый класс для исключений, которые возникают, когда ключ или индекс, используемые в отображении или последовательности, недопустимы: IndexError
, KeyError
. Исключение LookupError
можно поднять напрямую codecs.lookup()
.
Improve Article
Save Article
Improve Article
Save Article
All instances in Python must be instances of a class that derives from BaseException. Two exception classes that are not related via subclassing are never equivalent, even if they have the same name. The built-in exceptions can be generated by the interpreter or built-in functions.
There are several built-in exceptions in Python that are raised when errors occur. These built-in exceptions can be viewed using the local() built-in functions as follows :
>>> locals()['__builtins__']
This returns a dictionary of built-in exceptions, functions and attributes.
Base Classes
The following exceptions are used mostly as base classes for other exceptions.
- exception BaseException
This is the base class for all built-in exceptions. It is not meant to be directly inherited by user-defined classes. For, user-defined classes, Exception is used. This class is responsible for creating a string representation of the exception using str() using the arguments passed. An empty string is returned if there are no arguments.- args : The args are the tuple of arguments given to the exception constructor.
- with_traceback(tb) : This method is usually used in exception handling. This method sets tb as the new traceback for the exception and returns the exception object.
Code :
try: ... except SomeException: tb = sys.exc_info()[2] raise OtherException(...).with_traceback(tb)
- exception Exception
This is the base class for all built-in non-system-exiting exceptions. All user-defined exceptions should also be derived from this class. - exception ArithmeticError
This class is the base class for those built-in exceptions that are raised for various arithmetic errors such as :- OverflowError
- ZeroDivisionError
- FloatingPointError
Example :
try
:
a
=
10
/
0
print
(a)
except
ArithmeticError:
print
(
"This statement is raising an arithmetic exception."
)
else
:
print
(
"Success."
)
Output :
This statement is raising an arithmetic exception.
- exception BufferError
This exception is raised when buffer related operations cannot be performed. - exception LookupError
This is the base class for those exceptions that are raised when a key or index used on a mapping or sequence is invalid or not found. The exceptions raised are :- KeyError
- IndexError
Example :
try
:
a
=
[
1
,
2
,
3
]
print
(a[
3
])
except
LookupError:
print
(
"Index out of bound error."
)
else
:
print
(
"Success"
)
Output :
Index out of bound error.
Concrete exceptions
The following exceptions are the exceptions that are usually raised.
- exception AssertionError
An AssertionError is raised when an assert statement fails.Example :
assert False, 'The assertion failed'
Output :
Traceback (most recent call last): File "exceptions_AssertionError.py", line 12, in assert False, 'The assertion failed' AssertionError: The assertion failed
- exception AttributeError
An AttributeError is raised when an attribute reference or assignment fails such as when a non-existent attribute is referenced.Example :
class
Attributes(
object
):
pass
object
=
Attributes()
print
(
object
.attribute)
Output :
Traceback (most recent call last): File "d912bae549a2b42953bc62da114ae7a7.py", line 5, in print object.attribute AttributeError: 'Attributes' object has no attribute 'attribute'
- exception EOFError
An EOFError is raised when built-in functions like input() hits an end-of-file condition (EOF) without reading any data. The file methods like readline() return an empty string when they hit EOF.Example :
while
True
:
data
=
input
(
'Enter name : '
)
print
(
'Hello '
, data)
Output :
Enter Name :Hello Aditi Enter Name :Traceback (most recent call last): File "exceptions_EOFError.py", line 13, in data = raw_input('Enter name :') EOFError: EOF when reading a line
- exception FloatingPointError
A FloatingPointError is raised when a floating point operation fails. This exception is always defined, but can only be raised when Python is configured with the–with-fpectl option, or the WANT_SIGFPE_HANDLER symbol is defined in the pyconfig.h file.Example :
import
math
print
(math.exp(
1000
))
Output :
Traceback (most recent call last): File "", line 1, in FloatingPointError: in math_1
- exception GeneratorExit
This exception directly inherits from BaseException instead of Exception since it is technically not an error. A GeneratorExit exception is raised when a generator or coroutine is closed.Example :
def
my_generator():
try
:
for
i
in
range
(
5
):
print
(
'Yielding'
, i)
yield
i
except
GeneratorExit:
print
(
'Exiting early'
)
g
=
my_generator()
print
(g.
next
())
g.close()
Output :
Yielding 0 0 Exiting early
- exception ImportError
An ImportError is raised when the import statement is unable to load a module or when the “from list” in from … import has a name that cannot be found.Example :
import
module_does_not_exist
Output :
Traceback (most recent call last): File "exceptions_ImportError_nomodule.py", line 12, in import module_does_not_exist ImportError: No module named module_does_not_exist
Example :
from
exceptions
import
Userexception
Output :
Traceback (most recent call last): File "exceptions_ImportError_missingname.py", line 12, in from exceptions import Userexception ImportError: cannot import name Userexception
- exception ModuleNotFoundError
This is the subclass of ImportError which is raised by import when a module could not be found. It is also raised when None is found in sys.modules. - exception IndexError
An IndexError is raised when a sequence is referenced which is out of range.Example :
array
=
[
0
,
1
,
2
]
print
(array[
3
])
Output :
Traceback (most recent call last): File "exceptions_IndexError.py", line 13, in print array[3] IndexError: list index out of range
- exception KeyError
A KeyError is raised when a mapping key is not found in the set of existing keys.Example :
array
=
{
'a'
:
1
,
'b'
:
2
}
print
(array[
'c'
])
Output :
Traceback (most recent call last): File "exceptions_KeyError.py", line 13, in print array['c'] KeyError: 'c'
- exception KeyboardInterrupt
This error is raised when the user hits the interrupt key such as Control-C or Delete.Example :
try
:
print
(
'Press Return or Ctrl-C:'
,)
ignored
=
input
()
except
Exception, err:
print
(
'Caught exception:'
, err)
except
KeyboardInterrupt, err:
print
(
'Caught KeyboardInterrupt'
)
else
:
print
(
'No exception'
)
Output :
Press Return or Ctrl-C: ^CCaught KeyboardInterrupt
- exception MemoryError
This error is raised when an operation runs out of memory.Example :
def
fact(a):
factors
=
[]
for
i
in
range
(
1
, a
+
1
):
if
a
%
i
=
=
0
:
factors.append(i)
return
factors
num
=
600851475143
print
(fact(num))
Output :
Traceback (most recent call last): File "4af5c316c749aff128df20714536b8f3.py", line 9, in print fact(num) File "4af5c316c749aff128df20714536b8f3.py", line 3, in fact for i in range(1, a+1): MemoryError
- exception NameError
This error is raised when a local or global name is not found. For example, an unqualified variable name.Example :
def
func():
print
ans
func()
Output :
Traceback (most recent call last): File "cfba0a5196b05397e0a23b1b5b8c7e19.py", line 4, in func() File "cfba0a5196b05397e0a23b1b5b8c7e19.py", line 2, in func print ans NameError: global name 'ans' is not defined
- exception NotImplementedError
This exception is derived from RuntimeError. Abstract methods in user defined classed should raise this exception when the derived classes override the method.Example :
class
BaseClass(
object
):
def
__init__(
self
):
super
(BaseClass,
self
).__init__()
def
do_something(
self
):
raise
NotImplementedError(
self
.__class__.__name__
+
'.do_something'
)
class
SubClass(BaseClass):
def
do_something(
self
):
print
(
self
.__class__.__name__
+
' doing something!'
)
SubClass().do_something()
BaseClass().do_something()
Output :
Traceback (most recent call last): File "b32fc445850cbc23cd2f081ba1c1d60b.py", line 16, in BaseClass().do_something() File "b32fc445850cbc23cd2f081ba1c1d60b.py", line 7, in do_something raise NotImplementedError(self.__class__.__name__ + '.do_something') NotImplementedError: BaseClass.do_something
- exception OSError([arg])
The OSError exception is raised when a system function returns a system-related error, including I/O failures such as “file not found” or “disk full” errors.Example :
def
func():
print
(ans)
func()
Output :
Traceback (most recent call last): File "442eccd7535a2704adbe372cb731fc0f.py", line 4, in print i, os.ttyname(i) OSError: [Errno 25] Inappropriate ioctl for device
- exception OverflowError
The OverflowError is raised when the result of an arithmetic operation is out of range. Integers raise MemoryError instead of OverflowError. OverflowError is sometimes raised for integers that are outside a required range. Floating point operations are not checked because of the lack of standardization of floating point exception handling in C.Example :
import
sys
print
(
'Regular integer: (maxint=%s)'
%
sys.maxint)
try
:
i
=
sys.maxint
*
3
print
(
'No overflow for '
,
type
(i),
'i ='
, i)
except
OverflowError, err:
print
(
'Overflowed at '
, i, err)
print
()
print
(
'Long integer:'
)
for
i
in
range
(
0
,
100
,
10
):
print
(
'%2d'
%
i,
2L
*
*
i)
print
()
print
(
'Floating point values:'
)
try
:
f
=
2.0
*
*
i
for
i
in
range
(
100
):
print
(i, f)
f
=
f
*
*
2
except
OverflowError, err:
print
(
'Overflowed after '
, f, err)
Output :
Regular integer: (maxint=9223372036854775807) No overflow for i = 27670116110564327421 Long integer: 0 1 10 1024 20 1048576 30 1073741824 40 1099511627776 50 1125899906842624 60 1152921504606846976 70 1180591620717411303424 80 1208925819614629174706176 90 1237940039285380274899124224 Floating point values: 0 1.23794003929e+27 1 1.53249554087e+54 2 2.34854258277e+108 3 5.5156522631e+216 Overflowed after 5.5156522631e+216 (34, 'Numerical result out of range')
- exception RecursionError
The RecursionError is derived from the RuntimeError. This exception is raised when the interpreter detects that the maximum recursion depth is exceeded. - exception ReferenceError
The ReferenceError is raised when a weak reference proxy is used to access an attribute of the referent after the garbage collection.Example :
import
gc
import
weakref
class
Foo(
object
):
def
__init__(
self
, name):
self
.name
=
name
def
__del__(
self
):
print
(
'(Deleting %s)'
%
self
)
obj
=
Foo(
'obj'
)
p
=
weakref.proxy(obj)
print
(
'BEFORE:'
, p.name)
obj
=
None
print
(
'AFTER:'
, p.name)
Output :
BEFORE: obj (Deleting ) AFTER: Traceback (most recent call last): File "49d0c29d8fe607b862c02f4e1cb6c756.py", line 17, in print 'AFTER:', p.name ReferenceError: weakly-referenced object no longer exists
- exception RuntimeError
The RuntimeError is raised when no other exception applies. It returns a string indicating what precisely went wrong. - exception StopIteration
The StopIteration error is raised by built-in function next() and an iterator‘s __next__() method to signal that all items are produced by the iterator.Example :
Arr
=
[
3
,
1
,
2
]
i
=
iter
(Arr)
print
(i)
print
(i.
next
())
print
(i.
next
())
print
(i.
next
())
print
(i.
next
())
Output :
3 1 2 Traceback (most recent call last): File "2136fa9a620e14f8436bb60d5395cc5b.py", line 8, in print i.next() StopIteration
- exception SyntaxError
The SyntaxError is raised when the parser encounters a syntax error. A syntax error may occur in an import statement or while calling the built-in functions exec() or eval(), or when reading the initial script or standard input.Example :
try
:
print
(
eval
(
'geeks for geeks'
))
except
SyntaxError, err:
print
(
'Syntax error %s (%s-%s): %s'
%
(err.filename, err.lineno, err.offset, err.text))
print
(err)
Output :
Syntax error (1-9): geeks for geeks invalid syntax (, line 1)
- exception SystemError
The SystemError is raised when the interpreter finds an internal error. The associated value is a string indicating what went wrong. - exception SystemExit
The SystemExit is raised when sys.exit() function is called. A call to sys.exit() is translated into an exception to execute clean-up handlers (finally clauses of try statements) and to debug a script without running the risk of losing control. - exception TypeError
TypeError is raised when an operation or function is applied to an object of inappropriate type. This exception returns a string giving details about the type mismatch.Example :
arr
=
(
'tuple'
, )
+
'string'
print
(arr)
Output :
Traceback (most recent call last): File "30238c120c0868eba7e13a06c0b1b1e4.py", line 1, in arr = ('tuple', ) + 'string' TypeError: can only concatenate tuple (not "str") to tuple
- exception UnboundLocalError
UnboundLocalError is a subclass of NameError which is raised when a reference is made to a local variable in a function or method, but no value has been assigned to that variable.Example :
def
global_name_error():
print
(unknown_global_name)
def
unbound_local():
local_val
=
local_val
+
1
print
(local_val)
try
:
global_name_error()
except
NameError, err:
print
(
'Global name error:'
, err)
try
:
unbound_local()
except
UnboundLocalError, err:
print
(
'Local name error:'
, err)
Output :
Global name error: global name 'unknown_global_name' is not defined Local name error: local variable 'local_val' referenced before assignment
- exception UnicodeError
This exception is a subclass of ValueError. UnicodeError is raised when a Unicode-related encoding or decoding error occurs. - exception ValueError
A ValueError is raised when a built-in operation or function receives an argument that has the right type but an invalid value.Example :
Output :
Traceback (most recent call last): File "44f00efda935715a3c5468d899080381.py", line 1, in print int('a') ValueError: invalid literal for int() with base 10: 'a'
- exception ZeroDivisionError
A ZeroDivisionError is raised when the second argument of a division or modulo operation is zero. This exception returns a string indicating the type of the operands and the operation.Example :
Output :
Traceback (most recent call last): File "c31d9626b41e53d170a78eac7d98cb85.py", line 1, in print 1/0 ZeroDivisionError: integer division or modulo by zero
This article is contributed by Aditi Gupta. If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
Three years after my definitive guide on Python classic, static, class and abstract methods, it seems to be time for a new one. Here, I would like to dissect and discuss Python exceptions.
Dissecting the base exceptions
In Python, the base exception class is named BaseException
. Being rarely used in any program or library, it ought to be considered as an implementation detail. But to discover how it’s implemented, you can go and read Objects/exceptions.c in the CPython source code. In that file, what is interesting is to see that the BaseException
class defines all the basic methods and attribute of exceptions. The basic well-known Exception
class is then simply defined as a subclass of BaseException
, nothing more:
/*
* Exception extends BaseException
*/
SimpleExtendsException(PyExc_BaseException, Exception,
"Common base class for all non-exit exceptions.");
The only other exceptions that inherits directly from BaseException
are GeneratorExit
, SystemExit
and KeyboardInterrupt
. All the other builtin exceptions inherits from Exception
. The whole hierarchy can be seen by running pydoc2 exceptions
or pydoc3 builtins
.
Here are the graph representing the builtin exceptions inheritance in Python 2 and Python 3 (generated using this script).
The BaseException.__init__
signature is actually BaseException.__init__(*args)
. This initialization method stores any arguments that is passed in the args
attribute of the exception. This can be seen in the exceptions.c
source code – and is true for both Python 2 and Python 3:
static int
BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds)
{
if (!_PyArg_NoKeywords(Py_TYPE(self)->tp_name, kwds))
return -1;
Py_INCREF(args);
Py_XSETREF(self->args, args);
return 0;
}
The only place where this args
attribute is used is in the BaseException.__str__
method. This method uses self.args
to convert an exception to a string:
static PyObject *
BaseException_str(PyBaseExceptionObject *self)
{
switch (PyTuple_GET_SIZE(self->args)) {
case 0:
return PyUnicode_FromString("");
case 1:
return PyObject_Str(PyTuple_GET_ITEM(self->args, 0));
default:
return PyObject_Str(self->args);
}
}
This can be translated in Python to:
def __str__(self):
if len(self.args) == 0:
return ""
if len(self.args) == 1:
return str(self.args[0])
return str(self.args)
Therefore, the message to display for an exception should be passed as the first and the only argument to the BaseException.__init__
method.
Defining your exceptions properly
As you may already know, in Python, exceptions can be raised in any part of the program. The basic exception is called Exception
and can be used anywhere in your program. In real life, however no program nor library should ever raise Exception
directly: it’s not specific enough to be helpful.
Since all exceptions are expected to be derived from the base class Exception
, this base class can easily be used as a catch-all:
try:
do_something()
except Exception:
# THis will catch any exception!
print("Something terrible happened")
To define your own exceptions correctly, there are a few rules and best practice that you need to follow:
- Always inherit from (at least)
Exception
:
class MyOwnError(Exception):
pass
-
Leverage what we saw earlier about
BaseException.__str__
: it uses the first argument passed toBaseException.__init__
to be printed, so always callBaseException.__init__
with only one argument. -
When building a library, define a base class inheriting from
Excepion
. It will make it easier for consumers to catch any exception from the library:
class ShoeError(Exception):
"""Basic exception for errors raised by shoes"""
class UntiedShoelace(ShoeError):
"""You could fall"""
class WrongFoot(ShoeError):
"""When you try to wear your left show on your right foot"""
It then makes it easy to use except ShoeError
when doing anything with that piece of code related to shoes. For example, Django does not do that for some of its exceptions, making it hard to catch «any exception raised by Django».
- Provide details about the error. This is extremely valuable to be able to log correctly errors or take further action and try to recover:
class CarError(Exception):
"""Basic exception for errors raised by cars"""
def __init__(self, car, msg=None):
if msg is None:
# Set some default useful error message
msg = "An error occured with car %s" % car
super(CarError, self).__init__(msg)
self.car = car
class CarCrashError(CarError):
"""When you drive too fast"""
def __init__(self, car, other_car, speed):
super(CarCrashError, self).__init__(
car, msg="Car crashed into %s at speed %d" % (other_car, speed))
self.speed = speed
self.other_car = other_car
Then, any code can inspect the exception to take further action:
try:
drive_car(car)
except CarCrashError as e:
# If we crash at high speed, we call emergency
if e.speed >= 30:
call_911()
For example, this is leveraged in Gnocchi to raise specific application exceptions (NoSuchArchivePolicy
) on expected foreign key violations raised by SQL constraints:
try:
with self.facade.writer() as session:
session.add(m)
except exception.DBReferenceError as e:
if e.constraint == 'fk_metric_ap_name_ap_name':
raise indexer.NoSuchArchivePolicy(archive_policy_name)
raise
- Inherits from builtin exceptions types when it makes sense. This makes it easier for programs to not be specific to your application or library:
class CarError(Exception):
"""Basic exception for errors raised by cars"""
class InvalidColor(CarError, ValueError):
"""Raised when the color for a car is invalid"""
That allows many programs to catch errors in a more generic way without noticing your own defined type. If a program already knows how to handle a ValueError
, it won’t need any specific code nor modification.
Organization
Organizing code can be quite touchy and complicated. I cover more general rules in The Hacker’s Guide to Python, but here’s a few rules concerning exceptions in particular.
There is no limitation on where and when you can define exceptions. As they are, after all, normal classes, they can be defined in any module, function or class – even as closures.
Most libraries package their exceptions into a specific exception module: SQLAlchemy has them in
sqlalchemy.exc
, requests has them in
requests.exceptions
, Werkzeug has them in werkzeug.exceptions
, etc.
That makes sense for libraries to export exceptions that way, as it makes it very easy for consumers to import their exception module and know where the exceptions are defined when writing code to handle errors.
This is not mandatory, and smaller Python modules might want to retain their exceptions into their sole module. Typically, if your module is small enough to be kept in one file, don’t bother splitting your exceptions into a different file/module.
While this wisely applies to libraries, applications tend to be different beasts. Usually, they are composed of different subsystems, where each one might have its own set of exceptions. This is why I generally discourage going with only one exception module in an application, but to split them across the different parts of one’s program. There might be no need of a special myapp.exceptions
module.
For example, if your application is composed of an HTTP REST API defined into the module myapp.http
and of a TCP server contained into myapp.tcp
, it’s likely they can both define different exceptions tied to their own protocol errors and cycle of life. Defining those exceptions in a myapp.exceptions
module would just scatter the code for the sake of some useless consistency. If the exceptions are local to a file, just define them somewhere at the top of that file. It will simplify the maintenance of the code.
Wrapping exceptions
Wrapping exception is the practice by which one exception is encapsulated into another:
class MylibError(Exception):
"""Generic exception for mylib"""
def __init__(self, msg, original_exception):
super(MylibError, self).__init__(msg + (": %s" % original_exception))
self.original_exception = original_exception
try:
requests.get("http://example.com")
except requests.exceptions.ConnectionError as e:
raise MylibError("Unable to connect", e)
This makes sense when writing a library which leverages other libraries. If a library uses requests
and does not encapsulate requests
exceptions into its own defined error classes, it will be a case of layer violation. Any application using your library might receive a requests.exceptions.ConnectionError
, which is a problem because:
- The application has no clue that the library was using
requests
and does not need/want to know about it. - The application will have to import
requests.exceptions
itself and therefore will depend onrequests
– even if it does not use it directly. - As soon as
mylib
changes fromrequests
to e.g.httplib2
, the application code catchingrequests
exceptions will become irrelevant.
The Tooz library is a good example of wrapping, as it uses a driver-based approach and depends on a lot of different Python modules to talk to different backends (ZooKeeper, PostgreSQL, etcd…).
Therefore, it wraps exception from other modules on every occasion into its own set of error classes. Python 3 introduced the raise from
form to help with that, and that’s what Tooz leverages to raise its own error.
It’s also possible to encapsulate the original exception into a custom defined exception, as done above. That makes the original exception available for inspection easily.
Catching and logging
When designing exceptions, it’s important to remember that they should be targeted both at humans and computers. That’s why they should include an explicit message, and embed as much information as possible. That will help to debug and write resilient programs that can pivot their behavior depending on the attributes of exception, as seen above.
Also, silencing exceptions completely is to be considered as bad practice. You should not write code like that:
try:
do_something()
except Exception:
# Whatever
pass
Not having any kind of information in a program where an exception occurs is a nightmare to debug.
If you use (and you should) the logging
library, you can use the exc_info
parameter to log a complete traceback when an exception occurs, which might help debugging on severe and unrecoverable failure:
try:
do_something()
except Exception:
logging.getLogger().error("Something bad happened", exc_info=True)
If you often forget on how to setup the logging
library, you should check out daiquiri.
Further reading
If you understood everything so far, congratulations, you might be ready to handle exception in Python! If you want to have a broader scope on exceptions and what Python misses, I encourage you to read about condition systems and discover the generalization of exceptions – that I hope we’ll see in Python one day!
I hope this will help you building better libraries and application. Feel free to shoot any question in the comment section!
List of built-in exceptions in Python 3.
Base Classes
These exceptions are generally used as base classes for other exceptions.
Exception | Description |
---|---|
BaseException |
The base class for all built-in exceptions. It is not meant to be directly inherited by user-defined classes (for that, use Exception below). |
Exception |
All built-in, non-system-exiting exceptions are derived from this class. All user-defined exceptions should also be derived from this class. |
ArithmeticError |
The base class for built-in exceptions that are raised for various arithmetic errors. These are: OverflowError , ZeroDivisionError , FloatingPointError . |
BufferError |
Raised when a buffer related operation cannot be performed. |
LookupError |
The base class for exceptions that are raised when a key or index used on a mapping or sequence is invalid. These are: IndexError and KeyError . |
Concrete Exceptions
These are the exceptions that are usually raised.
Exception | Description |
---|---|
AssertionError |
Raised when an assert statement fails. |
AttributeError |
Raised when an attribute reference or assignment fails. |
EOFError |
Raised when the input() function hits an end-of-file condition (EOF) without reading any data. |
FloatingPointError |
Raised when a floating point operation fails. |
GeneratorExit |
Raised when a generator or coroutine is closed. Technically, this is not an error, and the GeneratorExit exception directly inherits from BaseException instead of Exception . |
ImportError |
Raised when the import statement fails when trying to load a module. This exception is also raised when the from in from ... import has a name that cannot be found. |
ModuleNotFoundError |
A subclass of ImportError which is raised by import when a module could not be located. This exception is also raised when None is found in sys.modules . |
IndexError |
Raised when a sequence subscript is out of range. |
KeyError |
Raised when a mapping (dictionary) key is not found in the set of existing keys. |
KeyboardInterrupt |
Raised when the user hits the interrupt key (typically Control-C or Delete ). |
MemoryError |
Raised when an operation runs out of memory but the situation may still be rescued (by deleting some objects). |
NameError |
Raised when a local or global name is not found. This applies only to unqualified names. |
NotImplementedError |
This exception is derived from RuntimeError . In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method, or while the class is being developed to indicate that the real implementation still needs to be added. |
OSError() |
This exception is raised when a system function returns a system-related error, including I/O failures such as «file not found» or «disk full». |
OverflowError |
Raised when the result of an arithmetic operation is too large to be represented. |
RecursionError |
This exception is derived from RuntimeError . It is raised when the interpreter detects that the maximum recursion depth is exceeded. |
ReferenceError |
Raised when a weak reference proxy, created by the weakref.proxy() function, is used to access an attribute of the referent after it has been garbage collected. |
RuntimeError |
Raised when an error is detected that doesn’t fall in any of the other categories. |
StopIteration |
Raised by the next() function and an iterator’s __next__() method to signal that there are no further items produced by the iterator. |
StopAsyncIteration |
Must be raised by __anext__() method of an asynchronous iterator object to stop the iteration. |
SyntaxError |
Raised when the parser encounters a syntax error. |
IndentationError |
Base class for syntax errors related to incorrect indentation. This is a subclass of SyntaxError . |
TabError |
Raised when indentation contains an inconsistent use of tabs and spaces. This is a subclass of IndentationError . |
SystemError |
Raised when the interpreter finds an internal error, but it’s not serious enough to exit the interpreter. |
SystemExit |
This exception is raised by the sys.exit() function, and (when it is not handled) causes the Python interpreter to exit. |
TypeError |
Raised when an operation or function is applied to an object of inappropriate type. |
UnboundLocalError |
Raised when a reference is made to a local variable in a function or method, but no value has been bound to that variable. This is a subclass of NameError . |
UnicodeError |
Raised when a Unicode-related encoding or decoding error occurs. It is a subclass of ValueError . |
UnicodeEncodeError |
Raised when a Unicode-related error occurs during encoding. It is a subclass of UnicodeError . |
UnicodeDecodeError |
Raised when a Unicode-related error occurs during encoding. It is a subclass of UnicodeError . |
UnicodeTranslateError |
Raised when a Unicode-related error occurs during encoding. It is a subclass of UnicodeError . |
ValueError |
Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value, and the situation is not described by a more precise exception. |
ZeroDivisionError |
Raised when the second argument of a division or modulo operation is zero. |
OS Exceptions
These exceptions are subclasses of OSError
. They get raised depending on the actual system error code.
Exception | Description |
---|---|
BlockingIOError |
Raised when an operation would block on an object (e.g. socket) set for non-blocking operation. |
ChildProcessError |
Raised when an operation on a child process failed. |
ConnectionError |
A base class for connection-related issues. |
BrokenPipeError |
A subclass of ConnectionError , raised when trying to write on a pipe while the other end has been closed, or trying to write on a socket which has been shutdown for writing. |
ConnectionAbortedError |
A subclass of ConnectionError , raised when a connection attempt is aborted by the peer. |
ConnectionRefusedError |
A subclass of ConnectionError , raised when a connection is reset by the peer. |
FileExistsError |
Raised when trying to create a file or directory which already exists. |
FileNotFoundError |
Raised when a file or directory is requested but doesn’t exist. |
InterruptedError |
Raised when a system call is interrupted by an incoming signal. |
IsADirectoryError |
Raised when a file operation is requested on a directory. |
NotADirectoryError |
Raised when a directory operation is requested on something which is not a directory. |
PermissionError |
Raised when trying to run an operation without the adequate access rights. |
ProcessLookupError |
Raised when a given process doesn’t exist. |
TimeoutError |
Raised when a system function timed out at the system level. |
Warnings
The following exceptions are used as warning categories.
Exception | Description |
---|---|
Warning |
Base class for warning categories. |
UserWarning |
Base class for warnings generated by user code. |
DeprecationWarning |
Base class for warnings about deprecated features. |
PendingDeprecationWarning |
Base class for warnings about features which will be deprecated in the future. |
SyntaxWarning |
Base class for warnings about dubious syntax. |
RuntimeWarning |
Base class for warnings about dubious runtime behavior. |
FutureWarning |
Base class for warnings about constructs that will change semantically in the future. |
ImportWarning |
Base class for warnings about probable mistakes in module imports. |
UnicodeWarning |
Base class for warnings related to Unicode. |
BytesWarning |
Base class for warnings related to bytes and bytearray . |
ResourceWarning |
Base class for warnings related to resource usage. |
Exceptions refer to the events of errors experienced when executing a program. This Python Exceptions tutorial will overview different exceptions in Python and explain how to catch and mitigate them.
Table of contents
What are the exceptions in Python?
Exceptions are events of failure in your Python code that result from database corruption, broken network connectivity, corrupted data, memory exhaustion, and unsupported user inputs. The purpose of every developer is to catch and mitigate such exceptions to ensure that the final program runs smoothly.
If an exception occurs when an application runs, there is a risk of losing data, corrupting existing data, or even causing the application to crash.
Python allows developers to handle these exceptions using pre-defined exceptions and structured exception handling.
For example, it is always possible to predict the possible error in a Python program and work around it by prompting the user to use the correct input, default value or alternate a program execution flow.
The difference between syntax errors and exceptions in Python
Syntax errors and exceptions in Python refer to unwanted conditions when executing a program.
Syntax error refers to an error that terminates the execution of a program due to the use of the wrong Python syntax in the code.
The wrong syntax comprises wrong naming styles, incorrect Python keywords, and invalid program structure.
Let’s take a look at the example below to illustrate the syntax error:
age = 18
def check_age(age):
if age >= 18
print("Individual is an adult")
If you try to execute the program above, you’ll get the following error message:
File "syntax_error_example.py", line 4
if age >= 18
^
SyntaxError: invalid syntax
On the other hand, exceptions refer to errors in executing a program, even when a statement is syntactically correct.
If the developer handles exceptions in the code, they do not stop the program’s execution but can lead to a change in the normal flow of the program execution.
As we’ve mentioned, it is possible to handle exceptions in your Python code so they might not be fatal and might not stop Python program execution.
We’ll take a look at how to handle exceptions later, but for now, let’s take a look at what happens if we’re not handling potentially dangerous situations in the code:
x = "test"
for i in range(x):
print(i)
Execution of the code block above will lead to the following error message and terminate program execution:
Traceback (most recent call last):
File "exception_example_1.py", line 3, in <module>
for i in range(x):
TypeError: 'str' object cannot be interpreted as an integer
Python3 Exception Handling
Now, it’s time to look at how to handle exceptions in Python.
Try block syntax in Python
To handle exceptions in Python, you need to use a try-except
block, which has the following syntax:
try:
statement(s)
except [exception_class]:
statement(s)
else:
statement(s)
finally:
statement(s)
Here’s how these clauses work:
- The
try
clause runs the block of code where an error is expected to occur. except
clause used to define the type of exception expected from thetry
block of code.- If there’s no exception captured, the
else
statemetns block is executed finally
statements are always to be executed regardless of any exceptions caught in thetry
clause
Catching a single exception in Python
Python allows you to handle any exceptions.
For example, let’s take a look at a program that prompts the user to enter a number, and when the program cannot convert the number to an integer, it raises a ValueError
exception:
for i in range(5):
x = input("Type in a number: ")
try:
number = int(x)
except ValueError:
print("The value you entered ({}) cannot be converted to an integer".format(x))
Now, let’s try to execute our program:
Type in a number: uytfd
The value you entered (uytfd) cannot be converted to an integer
Type in a number: 5656
Type in a number: 435
Type in a number: dfdf
The value you entered (dfdf) cannot be converted to an integer
Type in a number: shs
The value you entered (shs) cannot be converted to an integer
If the user is typing something wrong, the try
block will try to catch an exception by checking the exception classes provided in the except
clause.
If an exception doesn’t match any declared exceptions in the except
clause, Python will stop program execution with the message unhandled exception
.
Keep in mind: when handling exceptions in except blocks, a base class type will catch any raised type of its subclasses. For example, the ArythmeticError
exception class will catch OverflowError
, FloatingPointError
, and ZeroDivisionError
exceptions.
Catching multiple exceptions in Python
A try
clause can have to have several except
clauses to catch different types of exceptions for the same block of code:
for i in range(5):
try:
x = int(input("Type in a number: "))
except (ValueError, TypeError, NameError):
print("One of the above exceptions was captured during execution")
Here’s an execution output:
Type in a number: 675
Type in a number: jgd
One of the above exceptions wa captured during execution
Type in a number: fg
One of the above exceptions wa captured during execution
Type in a number: 56
Type in a number: 98
In addition to that, it is possible to provide several except
clauses to capture multiple exceptions:
for i in range(2):
user_input = input("Type in a number: ")
try:
x = int(user_input)
y = set()
y[1] = x
except ValueError:
print("The value you entered ({}) cannot be converted to an integer".format(user_input))
except TypeError:
print("You can not modify sets!!!")
print("Program execution finished")
Now, let’s try to execute the program above:
Type in a number: asd
The value you entered (asd) cannot be converted to an integer
Type in a number: 1
You can not modify sets!!!
Program execution finished
Even if we provide a valid value, we still have an error in the code, which was caught by the second except
clause.
Catching all exceptions in Python
Sometimes we do not know what exception we can get during the code execution, but we need to catch the error and continue the execution flow.
In that case, you can use except
clause without providing an exception name, but it is not recommended to hide any issues in the code block.
However, if you have a strong need, it is possible to catch any exception:
import os
path = "/not/existing/path"
try:
for file in os.listdir(path):
f = open(os.path.join(path, file))
except ValueError:
print("Catching ValueError")
except:
print("Unexpected error happened")
print("Program execution finished")
Here’s the execution output:
Unexpected error happened
Program execution finished
Using the “else” clause in the “try” block
If you’d like to know if the code block has been executed without any errors, you can use else
statement after the except
clauses:
for i in range(2):
x = input("Type in a number: ")
try:
number = int(x)
except ValueError:
print("The value you entered ({}) cannot be converted to an integer".format(x))
else:
print("Code block executed without issues")
print("Program execution finished")
Program execution result:
Type in a number: asf
The value you entered (asf) cannot be converted to an integer
Type in a number: 1
Code block executed without issues
Program execution finished
Getting access to the exception class in Python
If you need to get access to the exception class during the exception-handling process, you can do it by using as
keyword in the except
clause:
try:
a = 2/0
except Exception as error:
print(f'Exception info: {error.__doc__}')
Here’s an expected output:
Exception info: Second argument to a division or modulo operation was zero.
The difference between else and finally in Python
Lastly, let’s illustrate how else
and finally
clauses are working:
for i in [0, 1]:
try:
result = 2 / i
except ZeroDivisionError:
print("Division by zero")
else:
print(f'Division result: {result}')
finally:
print("Executing finally clausen")
print("Program execution finished")
Here’s an execution output:
Division by zero
Executing finally clause
Division result: 2.0
Executing finally clause
Program execution finished
As you can see from the program execution, Python always executes the finally
clause statements. At the same time, Python runs the else
clause statements only when try block executed without any errors.
Such behavior allows using the finally
clause to define clean-up actions such as closing sockets, file descriptors, disconnecting from the database, etc.
Your Python code should have these cleanup actions and execute them at all times, irrespective of the circumstances.
How to catch SyntaxErrorexception in Python
It is hard to catch the SyntaxError
exception, but it is still possible if the SyntaxError
is thrown out of an eval
, exec
, or import
statements:
try:
import my_module
except SyntaxError:
print("Syntax error in my_module")
print("Program execution finished")
Now, if the code in my_module
Python module contains syntax errors, program execution will not break:
Syntax error in my_module
Program execution finished
Raising exceptionsin Python
You have an opportunity not only to catch and workaround exceptions but also to raise them. So, if you’d like to throw an error in Python, use the raise
keyword followed by the error or exception type.
A common example of when you need this is implementing a manager class that allows users to allocate a network from a certain IP pool.
If the manager can’t allocate the network, it makes sense to create a user-defined exception and raise it when the event occurs.
To raise an exception in Python, you need to use raise
statement.
The exception you can raise can be any class that derives from an Exception
.
A python program implicitly instantiates the constructor by passing an exception class with no arguments, for example:
raise TypeError
As soon as Python runs the statement above, it will produce the following error message:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError
Re-raising exceptions in Python
In some cases, you may need to re-raise an exception that you’re capturing with try-except
block.
That’s possible by using a raise
statement without providing an exception class:
try:
raise TypeError(10.578)
except TypeError:
print('A float number was not captured!')
raise
The code above will not only raise an exception but also print the reason for that exception:
A float number was not captured!
Traceback (most recent call last):
File "rerising_exceptions.py", line 2, in <module>
raise TypeError(10.578)
TypeError: 10.578
Chaining exceptions in Python
Chaining exceptions is useful when you need to transform exceptions.
You can specify an optional from
keyword in the raise
statement that allows you to re-raise the exception and change its type:
def example():
try:
x = input("Type in a number: ")
number = int(x)
except ValueError as e:
raise RuntimeError('User input parsing error occurred') from e
example()
Here’s an execution output:
Type in a number: asd
Traceback (most recent call last):
File "multiple_except.py", line 4, in example
number = int(x)
ValueError: invalid literal for int() with base 10: 'asd'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "multiple_except.py", line 8, in <module>
example()
File "multiple_except.py", line 6, in example
raise RuntimeError('A parsing error occurred') from e
RuntimeError: A parsing error occurred
Built-In Python exceptions
Most of the built-in exceptions are inheriting the BaseException
class. Python interpreter usually generates these exceptions from built-in functions to help developers identify the root cause of an error during Python program execution.
You can inherit built-in exception classes to define new exceptions. All Python developers are encouraged to derive new exceptions from the Exception
class or one of its subclasses but not from the BaseException
class.
Base exception classes in Python
The tree of base exception classes provides Python developers with lots of standard exceptions. In this part of the article, we’ll review the purpose of Python3 exceptions.
BaseException
is the base class for all the built-in exceptions. Python developers should not directly inherit this class to define any custom exception classes. This class creates a string representation of the exception by defining the str() method and its arguments. If there are no arguments Python will return an exception with an empty string.GeneratorExit
Python throws this exception when a coroutine or generator is closed. It inherits from the BaseException but not the Exception class because it is not an error.KeyboardInterrupt
– When a user hits the interrupt key such as Delete or Control+C, this error exception is raised.SystemExit
– When thesys.exit()
function is called, this exception is raised. In addition, calling this function indicates that clean-up handlers should be executed, that is, thefinally
clauses oftry
statements.Exception
– is a base class for all built-in non-system-exiting exceptions and user-defined exceptions
ArithmeticError
is the base exception class for arithmetic errors such asFloatingPointError
,ZeroDivisionError
, andOverflowError
.FloatingPointError
– you can catch this exception when the operation of a floating-point value fails. However, the exception is always defined and it can only be raised if theWANT_SIGFPE_HANDLER
symbol is defined in the pyconfig.h file.ZeroDivisionError
happens when second argument of the division or modulo operation equals zero
LookupError
defines a base class forIndexError
andKeyError
exceptions that raised by Python when developer is trying to manipulate non-existing or is invalidindex
orkey
values at sequence or mapping.IndexError
exception happens when a referenced sequence is out of rangeKeyError
you can catch this exception if a mapping key not found in the set of existing keysOverflowError
– this exception happens when the results from an arithmetic operation are out of range and also if integers are out of a required range
Concrete exceptions in Python
Concrete exceptions in Python are build-in exceptions that inherited directly from the Exception
class.
Here’s a quick description of all concrete exceptions:
BufferError
– Python throws this exception when a buffer-related operation fails to execute correctlyAssertionError
is raised when anassert
statement fails in Python codeValueError
– you can catch this exception when a built-in function or operation receives the correct type of argument but with an invalid valueUnicodeError
– This is a subclass ofValueError
and is raised when aUnicode
decoding or encoding error is captured.
TypeError
– Python throws this exception when developer apply an inappropriate type object to a function or an operation. Astring
that gives the details related to the mismatch is returned by this exception.SystemError
– Python throws this exception when the interpreter encounters an internal error.StopIteration
– The built-in functionnext()
and the iterator’s__next__()
method raise this exception to indicate that all items are produced by the iterator.RuntimeError
– raises when no other exception applies. Astring
is returned with the details of the actual problem encountered during execution.RecursionError
– Derived from theRuntimeError
and is raised when the maximum recursion depth has been exceeded.NotImplementedError
– The exception is derived from theRuntimeError
and is raised when derived classes override the abstract methods in user-defined classes.
SyntaxError
– you can catch this exception when an interpreter encounters wrong syntax. A syntax error can be experienced in an import statement or when reading a standard input or when calling the builtin functioneval()
orexec()
.
ReferenceError
– Python throws this exception when a weak reference proxy to accesses an attribute of the reference after the garbage collection.AttributeError
– you’re getting this exception whenever the assignment or reference of an attribute fails. This can happen because the referred attribute does not exist.MemoryError
– when Python runs out of memory it throws this exceptionEOFError
– TheEOFError
is raised if the built-in functions such asinput()
encounters an end-of-file (EOF) condition without reading any data. For instance, in case thereadline()
builtin function encounters an EOF, it returns an empty string.ImportError
– Raised when theimport
statement fails to load a module or when the from list in from import has a name that does not exist.ModuleNotFoundError
– It is a subclass of theImportError
and is raised when a module could not be found. In addition to that, if None is found insys.modules
the exception can also be raised.
NameError
– The exception is raised when aglobal
orlocal name
is not found.UnboundLocalError
– This exception is raised when a reference is made to a local variable in a method or a function but there is no value bound to that variable.
OSError([arg])
– Whenever a system function returns a system-related error such as I/O failures including “disk full” or “file not found” errors.FileNotFoundError
– Raised when a requested file directory or file does not exist.FileExistsError
– This exception is raised when attempting to create an already existing file or a directory.TimeoutError
– Raised when a system function timed out at the system level.PermissionError
– Raised when attempting to run an application without the required access rights.ConnectionError
– This is the base class for connection related issues and the subclasses are:BrokenPipeError
– Raised when attempting to write on a pipe closed on the other end. Also when attempting to write on a shut down socket.ConnectionResetError
– The exception is raised when a peer resets a connection.ConnectionAbortedError
– Raised when a peer aborts a connection attempt.ConnectionRefusedError
– Raised if a peer refuses a connection attempt.
ProcessLookupError
– It gets raised in case a specified process does not exist.InterruptedError
– The exception is raised when a system class is interrupted by an incoming signal. In Python 3.5+, Python retries system calls whenever a system call is interrupted.IsADirectoryError
– It is raised when a file operation such asos.remove()
is requested on a directory.NotADirectoryError
– Raised when a directory operation such asos.listdir()
is requested on an argument that is not a directory.ChildProcessError
– Gets raised when a child process operatio fails.BlockingIOError
– This error is raised when an operation would block on an object set for non-blocking operation.
Warnings in Python
Developers typically use warning messages when they need to alert the user about some important condition in a program. Usually, such a condition doesn’t raise an exception or terminate the program. A good example might be to print a warning when a program uses an obsolete Python module.
Here’s a list of built-in Python warnings:
FutureWarning
– This is the base class of warnings about deprecated features.BytesWarning
– Base class for warning related to bytearray and bytes.SyntaxWarning
– For dubious syntax, this is the base class of such warnings.ImportWarning
– Base class for warning related to probable mistakes in module imports.Warning
– Base class for warning categories.UserWarning
– This is the base class forwarnings
that have been generated by the user code.ResourceWarning
– Base class for warnings associated with resource usage.PendingDeprecationWarning
– This is the base class forwarnings
related to obsolete features that are expected to be deprecated in the future. For already active deprecation theDeprecationWarning
is used.DeprecationWarning
– Base class for the warning associated with deprecated features.UnicodeWarning
– Base class for warning related to Unicode.
User-defined exceptions in Python
You can inherit from any built-in exception class to create your own exception type.
User-defined exceptions allow us to display more relevant and detailed information when an exception occurs during program execution, for example:
class CustomError(Exception):
pass
raise CustomError('My custom error')
Here’s the program output:
Traceback (most recent call last):
File "multiple_except.py", line 4, in <module>
raise CustomError('My custom error')
__main__.CustomError: My custom error
Customizing exception classes in Python
If you’d like to implement more meaningful exception messages in your Python program, you can do it by implementing an exception class constructor:
ALLOWED_CAR_COLOURS = ['black', 'red', 'green']
class IncorrectCarColourException(Exception):
"""Exception raised for errors in the car colour input.
Attributes:
colour -- car colour
"""
def __init__(self, colour):
self.colour = colour
self.message = f'''
{self.colour} car colour is not allowed.
Allowed values are {ALLOWED_CAR_COLOURS}
'''
super().__init__(self.message)
car_color = input("Enter car colour: ")
if not car_color in ALLOWED_CAR_COLOURS:
raise IncorrectCarColourException(car_color)
Here’s an execution example:
Enter car colour: white
Traceback (most recent call last):
File "multiple_except.py", line 22, in <module>
raise IncorrectCarColourException(car_color)
__main__.IncorrectCarColourException:
white car colour is not allowed.
Allowed values are ['black', 'red', 'green']
Summary
We have seen different types of exceptions, both built-in and user-defined ones. In addition to that, we have reviewed specific exceptions and errors that occur to raise these exceptions. The article has a detailed explanation of how to handle and raise exceptions in a Python program.