Python 3 — exceptions handling
Содержание:
- What are exceptions in Python?
- The try-finally Clause
- Что такое Traceback в Python?
- 8.3. Handling Exceptions¶
- Built-in exceptions
- User-defined Exceptions
- Python try…finally
- Raising an Exceptions
- Python user defined exceptions
- Создание настраиваемого класса исключения
- Assertions in Python
- Other Changes
- Exceptions versus Syntax Errors
- Когда использовать исключения¶
- try/except¶
- Built-in Exceptions
- User-Defined Exceptions
- Base classes¶
What are exceptions in Python?
Python has built-in exceptions which can output an error. If an error occurs while running the program, it’s called an exception.
If an exception occurs, the type of exception is shown. Exceptions needs to be dealt with or the program will crash. To handle exceptions, the block is used.
Some exceptions you may have seen before are , or but there are many more.
All exceptions in Python inherit from the class BaseException. If you open the Python interactive shell and type the following statement it will list all built-in exceptions:
The idea of the try-except clause is to handle exceptions (errors at runtime). The syntax of the try-except block is:
1234 |
try: <do something>except Exception: <handle the error> |
The idea of the try-except block is this:
-
try: the code with the exception(s) to catch. If an exception is raised, it jumps straight into the except block.
-
except: this code is only executed if an exception occured in the try block. The except block is required with a try block, even if it contains only the pass statement.
It may be combined with the else and finally keywords.
-
else: Code in the else block is only executed if no exceptions were raised in the try block.
-
finally: The code in the finally block is always executed, regardless of if a an exception was raised or not.
The try-finally Clause
You can use a finally: block along with a try: block. The finally block is a place to put any code that must execute, whether the try-block
raised an exception or not. The syntax of the try-finally statement is this −
try: You do your operations here; ...................... Due to any exception, this may be skipped. finally: This would always be executed. ......................
You cannot use else clause as well along with a finally clause.
Example
#!/usr/bin/python try: fh = open("testfile", "w") fh.write("This is my test file for exception handling!!") finally: print "Error: can\'t find file or read data"
If you do not have permission to open the file in writing mode, then this will produce the following result −
Error: can't find file or read data
Same example can be written more cleanly as follows −
#!/usr/bin/python try: fh = open("testfile", "w") try: fh.write("This is my test file for exception handling!!") finally: print "Going to close the file" fh.close() except IOError: print "Error: can\'t find file or read data"
When an exception is thrown in the try block, the execution immediately passes to the finally block. After all the statements in the finally block are executed, the exception is raised again and is handled in the except statements if present in the next higher layer of the try-except statement.
Что такое Traceback в Python?
Трассировка (Traceback) — это отчет, содержащий вызовы функций, сделанные в вашем коде в определенный момент. Трассировка известна под многими именами, включая stack trace (трассировку стека), stack traceback (трассировку стека), backtrace (обратную трассировку) и, возможно, другие. В Python используется термин traceback.
Когда ваша программа выдает исключение, Python отображает трассировку, чтобы помочь вам узнать, что пошло не так. Ниже приведен пример, иллюстрирующий эту ситуацию:
# example.py def greet(someone): print('Hello, ' + someon) greet('Chad')
Здесь вызывается функция greet() с параметром someone. Однако в greet() это имя переменной не используется. Вместо этого было ошибочно указано переменная someon в вызове print().
Примечание. В этом руководстве предполагается, что вы знаете что такое исключения в Python. Если вы незнакомы или просто хотите освежиться, то вам следует почитать Python Exceptions: Введение.
Когда вы запустите эту программу, вы получите следующий traceback:
$ python example.py Traceback (most recent call last): File "/path/to/example.py", line 4, in <module> greet('Chad') File "/path/to/example.py", line 2, in greet print('Hello, ' + someon) NameError: name 'someon' is not defined
Этот вывод traceback содержит всю информацию, необходимую для диагностики проблемы. Последняя строка вывода сообщает вам, какой тип исключения был сгенерирован вместе с некоторой соответствующей информацией об этом исключении. Предыдущие строки указывают на код, который привел к возникновению исключения.
В приведенной выше traceback исключением был NameError, что означает, что имеется ссылка на какое-то имя (переменная, функция, класс), которое не было определено. В нашем примере использовано имя — someon.
В последней строке в этом случае достаточно информации, чтобы помочь вам решить проблему. Поиск кода по имени someon, который является орфографической ошибкой, укажет вам правильное направление. Однако часто ваш код намного сложнее.
8.3. Handling Exceptions¶
It is possible to write programs that handle selected exceptions. Look at the
following example, which asks the user for input until a valid integer has been
entered, but allows the user to interrupt the program (using Control-C or
whatever the operating system supports); note that a user-generated interruption
is signalled by raising the exception.
>>> while True ... try ... x = int(input("Please enter a number: ")) ... break ... except ValueError ... print("Oops! That was no valid number. Try again...") ...
The statement works as follows.
-
First, the try clause (the statement(s) between the and
keywords) is executed. -
If no exception occurs, the except clause is skipped and execution of the
statement is finished. -
If an exception occurs during execution of the try clause, the rest of the
clause is skipped. Then if its type matches the exception named after the
keyword, the except clause is executed, and then execution
continues after the statement. -
If an exception occurs which does not match the exception named in the except
clause, it is passed on to outer statements; if no handler is
found, it is an unhandled exception and execution stops with a message as
shown above.
A statement may have more than one except clause, to specify
handlers for different exceptions. At most one handler will be executed.
Handlers only handle exceptions that occur in the corresponding try clause, not
in other handlers of the same statement. An except clause may
name multiple exceptions as a parenthesized tuple, for example:
... except (RuntimeError, TypeError, NameError): ... pass
A class in an clause is compatible with an exception if it is
the same class or a base class thereof (but not the other way around — an
except clause listing a derived class is not compatible with a base class). For
example, the following code will print B, C, D in that order:
class B(Exception): pass class C(B): pass class D(C): pass for cls in B, C, D]: try raise cls() except D print("D") except C print("C") except B print("B")
Note that if the except clauses were reversed (with first), it
would have printed B, B, B — the first matching except clause is triggered.
The last except clause may omit the exception name(s), to serve as a wildcard.
Use this with extreme caution, since it is easy to mask a real programming error
in this way! It can also be used to print an error message and then re-raise
the exception (allowing a caller to handle the exception as well):
import sys try f = open('myfile.txt') s = f.readline() i = int(s.strip()) except OSError as err print("OS error: {0}".format(err)) except ValueError print("Could not convert data to an integer.") except print("Unexpected error:", sys.exc_info()[]) raise
The … statement has an optional else
clause, which, when present, must follow all except clauses. It is useful for
code that must be executed if the try clause does not raise an exception. For
example:
for arg in sys.argv1:]: try f = open(arg, 'r') except OSError print('cannot open', arg) else print(arg, 'has', len(f.readlines()), 'lines') f.close()
The use of the clause is better than adding additional code to
the clause because it avoids accidentally catching an exception
that wasn’t raised by the code being protected by the …
statement.
When an exception occurs, it may have an associated value, also known as the
exception’s argument. The presence and type of the argument depend on the
exception type.
The except clause may specify a variable after the exception name. The
variable is bound to an exception instance with the arguments stored in
. For convenience, the exception instance defines
so the arguments can be printed directly without having to
reference . One may also instantiate an exception first before
raising it and add any attributes to it as desired.
>>> try ... raise Exception('spam', 'eggs') ... except Exception as inst ... print(type(inst)) # the exception instance ... print(inst.args) # arguments stored in .args ... print(inst) # __str__ allows args to be printed directly, ... # but may be overridden in exception subclasses ... x, y = inst.args # unpack args ... print('x =', x) ... print('y =', y) ... <class 'Exception'> ('spam', 'eggs') ('spam', 'eggs') x = spam y = eggs
If an exception has arguments, they are printed as the last part (‘detail’) of
the message for unhandled exceptions.
Exception handlers don’t just handle exceptions if they occur immediately in the
try clause, but also if they occur inside functions that are called (even
indirectly) in the try clause. For example:
Built-in exceptions
Exception | Cause of Error |
---|---|
AssertionError | if statement fails. |
AttributeError | if attribute assignment or reference fails. |
EOFError | if the functions hits end-of-file condition. |
FloatingPointError | if a floating point operation fails. |
GeneratorExit | Raise if a generator’s method is called. |
ImportError | if the imported module is not found. |
IndexError | if index of a sequence is out of range. |
KeyError | if a key is not found in a dictionary. |
KeyboardInterrupt | if the user hits interrupt key (Ctrl+c or delete). |
MemoryError | if an operation runs out of memory. |
NameError | if a variable is not found in local or global scope. |
NotImplementedError | by abstract methods. |
OSError | if system operation causes system related error. |
OverflowError | if result of an arithmetic operation is too large to be represented. |
ReferenceError | if a weak reference proxy is used to access a garbage collected referent. |
RuntimeError | if an error does not fall under any other category. |
StopIteration | by function to indicate that there is no further item to be returned by iterator. |
SyntaxError | by parser if syntax error is encountered. |
IndentationError | if there is incorrect indentation. |
TabError | if indentation consists of inconsistent tabs and spaces. |
SystemError | if interpreter detects internal error. |
SystemExit | by function. |
TypeError | if a function or operation is applied to an object of incorrect type. |
UnboundLocalError | if a reference is made to a local variable in a function or method, but no value has been bound to that variable. |
UnicodeError | if a Unicode-related encoding or decoding error occurs. |
UnicodeEncodeError | if a Unicode-related error occurs during encoding. |
UnicodeDecodeError | if a Unicode-related error occurs during decoding. |
UnicodeTranslateError | if a Unicode-related error occurs during translating. |
ValueError | if a function gets argument of correct type but improper value. |
ZeroDivisionError | if second operand of division or modulo operation is zero. |
User-defined Exceptions
Python has many standard types of exceptions, but they may not always serve your purpose.Your program can have your own type of exceptions.
To create a user-defined exception, you have to create a class that inherits from Exception.
1234 |
class LunchError(Exception): passraise LunchError("Programmer went to lunch") |
You made a user-defined exception named LunchError in the above code. You can raise this new exception if an error occurs.
Outputs your custom error:
Your program can have many user-defined exceptions. The program below throws exceptions based on a new projects money:
1234567891011 |
class NoMoneyException(Exception): passclass OutOfBudget(Exception): passbalance = int(input("Enter a balance: "))if balance < 1000: raise NoMoneyExceptionelif balance > 10000: raise OutOfBudget |
Here are some sample runs:
It is a good practice to put all user-defined exceptions in a separate file (exceptions.py or errors.py). This is common practice in standard modules too.
If you are a beginner, then I highly recommend this book.
Python try…finally
The statement in Python can have an optional clause. This clause is executed no matter what, and is generally used to release external resources.
For example, we may be connected to a remote data center through the network or working with a file or a Graphical User Interface (GUI).
In all these circumstances, we must clean up the resource before the program comes to a halt whether it successfully ran or not. These actions (closing a file, GUI or disconnecting from network) are performed in the clause to guarantee the execution.
Here is an example of file operations to illustrate this.
This type of construct makes sure that the file is closed even if an exception occurs during the program execution.
Raising an Exceptions
You can raise exceptions in several ways by using the raise statement. The general syntax for the raise statement is as follows.
Syntax
raise ]]
Here, Exception is the type of exception (for example, NameError) and argument is a value for the exception argument. The argument is optional; if not supplied, the exception argument is None.
The final argument, traceback, is also optional (and rarely used in practice), and if present, is the traceback object used for the exception.
Example
An exception can be a string, a class or an object. Most of the exceptions that the Python core raises are classes, with an argument that is an instance of the class. Defining new exceptions is quite easy and can be done as follows −
def functionName( level ): if level < 1: raise "Invalid level!", level # The code below to this would not be executed # if we raise the exception
Note: In order to catch an exception, an «except» clause must refer to the same exception thrown either class object or simple string. For example, to capture above exception, we must write the except clause as follows −
try: Business Logic here... except "Invalid level!": Exception handling here... else: Rest of the code here...
Python user defined exceptions
We can create our own exceptions if we want. We do it by defining a
new exception class.
user_defined.py
#!/usr/bin/env python # user_defined.py class BFoundEx(Exception): def __init__(self, value): self.par = value def __str__(self): return f"BFoundEx: b character found at position {self.par}" string = "There are beautiful trees in the forest." pos = 0 for i in string: try: if i == 'b': raise BFoundEx(pos) pos = pos + 1 except BFoundEx as e: print(e)
In our code example, we have created a new exception. The exception is derived
from the base class. If we find any occurrence of
letter b in a string, we our exception.
$ ./user_defined.py 'BFoundEx: b character found at position 10'
Создание настраиваемого класса исключения
Мы можем создать собственный класс исключения, расширив класс Exception. Лучше всего создать базовое исключение, а затем наследовать другие классы. Вот несколько примеров.
class EmployeeModuleError(Exception): """Base Exception Class for our Employee module""" pass class EmployeeNotFoundError(EmployeeModuleError): """Error raised when employee is not found in the database""" def __init__(self, emp_id, msg): self.employee_id = emp_id self.error_message = msg class EmployeeUpdateError(EmployeeModuleError): """Error raised when employee update fails""" def __init__(self, emp_id, sql_error_code, sql_error_msg): self.employee_id = emp_id self.error_message = sql_error_msg self.error_code = sql_error_code
По соглашению об именах к имени класса исключения добавляется суффикс «Ошибка».
Assertions in Python
An assertion is a sanity-check that you can turn on or turn off when you are done with your testing of the program.
-
The easiest way to think of an assertion is to liken it to a raise-if statement (or to be more accurate, a raise-if-not statement). An expression is tested, and if the result comes up false, an exception is raised.
-
Assertions are carried out by the assert statement, the newest keyword to Python, introduced in version 1.5.
-
Programmers often place assertions at the start of a function to check for valid input, and after a function call to check for valid output.
The assert Statement
When it encounters an assert statement, Python evaluates the accompanying expression, which is hopefully true. If the expression is false, Python raises an AssertionError exception.
The syntax for assert is −
assert Expression
If the assertion fails, Python uses ArgumentExpression as the argument for the AssertionError. AssertionError exceptions can be caught and handled like any other exception, using the try-except statement. If they are not handled, they will terminate the program and produce a traceback.
Example
Here is a function that converts a given temperature from degrees Kelvin to degrees Fahrenheit. Since 0° K is as cold as it gets, the function bails out if it sees a negative temperature −
#!/usr/bin/python3 def KelvinToFahrenheit(Temperature): assert (Temperature >= 0),"Colder than absolute zero!" return ((Temperature-273)*1.8)+32 print (KelvinToFahrenheit(273)) print (int(KelvinToFahrenheit(505.78))) print (KelvinToFahrenheit(-5))
When the above code is executed, it produces the following result −
32.0 451 Traceback (most recent call last): File "test.py", line 9, in <module> print KelvinToFahrenheit(-5) File "test.py", line 4, in KelvinToFahrenheit assert (Temperature >= 0),"Colder than absolute zero!" AssertionError: Colder than absolute zero!
Other Changes
Some changes to the language were made as part of the same project.
New Builtin Functions
Two new intrinsic functions for class testing were introduced
(since the functionality had to be implemented in the C API, there was
no reason not to make it accessible to Python programmers).
returns true iff class D is derived
from class C,
directly or indirectly. issubclass(C, C) always returns true. Both
arguments must be class objects.
returns true iff x is an
instance of C or of a
(direct or indirect) subclass of C. The first argument may hyave any
type; if x is not an instance of any class, isinstance(x, C) always
returns false. The second argument must be a class object.
Sequence Unpacking
Previous Python versions require an exact type match between the
left hand and right hand side of «unpacking» assignments, e.g.
As part of the same project, the right hand side of either statement can be
any sequence with exactly three items. This makes it possible to
extract e.g. the errno and strerror values from an IOError exception
in a backwards compatible way:
The same approach works for the SyntaxError exception, with the
proviso that the info part is not always present:
Exceptions versus Syntax Errors
Syntax errors occur when the parser detects an incorrect statement. Observe the following example:
The arrow indicates where the parser ran into the syntax error. In this example, there was one bracket too many. Remove it and run your code again:
This time, you ran into an exception error. This type of error occurs whenever syntactically correct Python code results in an error. The last line of the message indicated what type of exception error you ran into.
Instead of showing the message , Python details what type of exception error was encountered. In this case, it was a . Python comes with various built-in exceptions as well as the possibility to create self-defined exceptions.
Когда использовать исключения¶
Как правило, один и тот же код можно написать и с использованием
исключений, и без них.
Например, этот вариант кода:
while True a = input("Введите число: ") b = input("Введите второе число: ") try result = int(a)int(b) except ValueError print("Поддерживаются только числа") except ZeroDivisionError print("На ноль делить нельзя") else print(result) break
Можно переписать таким образом без try/except (файл
try_except_divide.py):
while True a = input("Введите число: ") b = input("Введите второе число: ") if a.isdigit() and b.isdigit(): if int(b) == print("На ноль делить нельзя") else print(int(a)int(b)) break else print("Поддерживаются только числа")
Но далеко не всегда аналогичный вариант без использования исключений
будет простым и понятным.
Важно в каждой конкретной ситуации оценивать, какой вариант кода более
понятный, компактный и универсальный — с исключениями или без
try/except¶
Если вы повторяли примеры, которые использовались ранее, то наверняка
были ситуации, когда выскакивала ошибка. Скорее всего, это была ошибка
синтаксиса, когда не хватало, например, двоеточия.
Как правило, Python довольно понятно реагирует на подобные ошибки, и их
можно исправить.
Тем не менее, даже если код синтаксически написан правильно, могут
возникать ошибки. В Python эти ошибки называются исключения (exceptions).
Примеры исключений:
In 1]: 2 ----------------------------------------------------- ZeroDivisionError division by zero In 2]: 'test' + 2 ----------------------------------------------------- TypeError must be str, not int
В данном случае возникло два исключения: ZeroDivisionError и
TypeError.
Чаще всего можно предсказать, какого рода исключения возникнут во время
исполнения программы.
Например, если программа на вход ожидает два числа, а на выходе выдает
их сумму, а пользователь ввел вместо одного из чисел строку, появится
ошибка TypeError, как в примере выше.
Python позволяет работать с исключениями. Их можно перехватывать и
выполнять определенные действия в том случае, если возникло исключение.
Примечание
Когда в программе возникает исключение, она сразу завершает работу.
Для работы с исключениями используется конструкция :
In 3]: try ... 2 ... except ZeroDivisionError ... print("You can't divide by zero") ... You can't divide by zero
Конструкция try работает таким образом:
- сначала выполняются выражения, которые записаны в блоке try
- если при выполнения блока try не возникло никаких исключений, блок except пропускается,
и выполняется дальнейший код - если во время выполнения блока try в каком-то месте возникло исключение,
оставшаяся часть блока try пропускается- если в блоке except указано исключение, которое возникло, выполняется код в блоке except
- если исключение, которое возникло, не указано в блоке except,
выполнение программы прерывается и выдается ошибка
Обратите внимание, что строка в блоке try не выводится:
In 4]: try ... print("Let's divide some numbers") ... 2 ... print('Cool!') ... except ZeroDivisionError ... print("You can't divide by zero") ... Let's divide some numbers You can't divide by zero
В конструкции try/except может быть много except, если нужны разные
действия в зависимости от типа ошибки.
Например, скрипт divide.py делит два числа введенных пользователем:
# -*- coding: utf-8 -*- try a = input("Введите первое число: ") b = input("Введите второе число: ") print("Результат: ", int(a)int(b)) except ValueError print("Пожалуйста, вводите только числа") except ZeroDivisionError print("На ноль делить нельзя")
Примеры выполнения скрипта:
$ python divide.py Введите первое число: 3 Введите второе число: 1 Результат: 3 $ python divide.py Введите первое число: 5 Введите второе число: 0 На ноль делить нельзя $ python divide.py Введите первое число: qewr Введите второе число: 3 Пожалуйста, вводите только числа
В данном случае исключение ValueError возникает, когда пользователь
ввел строку вместо числа, во время перевода строки в число.
Исключение ZeroDivisionError возникает в случае, если второе число было
равным 0.
Если нет необходимости выводить различные сообщения на ошибки ValueError
и ZeroDivisionError, можно сделать так (файл divide_ver2.py):
# -*- coding: utf-8 -*- try a = input("Введите первое число: ") b = input("Введите второе число: ") print("Результат: ", int(a)int(b)) except (ValueError, ZeroDivisionError): print("Что-то пошло не так...")
Проверка:
$ python divide_ver2.py Введите первое число: wer Введите второе число: 4 Что-то пошло не так... $ python divide_ver2.py Введите первое число: 5 Введите второе число: 0 Что-то пошло не так...
Built-in Exceptions
The table below shows built-in exceptions that are usually raised in Python:
Exception | Description |
---|---|
ArithmeticError | Raised when an error occurs in numeric calculations |
AssertionError | Raised when an assert statement fails |
AttributeError | Raised when attribute reference or assignment fails |
Exception | Base class for all exceptions |
EOFError |
Raised when the input() method hits an «end of file» condition (EOF) |
FloatingPointError | Raised when a floating point calculation fails |
GeneratorExit | Raised when a generator is closed (with the close() method) |
ImportError | Raised when an imported module does not exist |
IndentationError | Raised when indendation is not correct |
IndexError | Raised when an index of a sequence does not exist |
KeyError | Raised when a key does not exist in a dictionary |
KeyboardInterrupt |
Raised when the user presses Ctrl+c, Ctrl+z or Delete |
LookupError | Raised when errors raised cant be found |
MemoryError | Raised when a program runs out of memory |
NameError | Raised when a variable does not exist |
NotImplementedError |
Raised when an abstract method requires an inherited class to override the method |
OSError | Raised when a system related operation causes an error |
OverflowError | Raised when the result of a numeric calculation is too large |
ReferenceError | Raised when a weak reference object does not exist |
RuntimeError | Raised when an error occurs that do not belong to any specific expections |
StopIteration | Raised when the next() method of an iterator has no further values |
SyntaxError | Raised when a syntax error occurs |
TabError | Raised when indentation consists of tabs or spaces |
SystemError | Raised when a system error occurs |
SystemExit | Raised when the sys.exit() function is called |
TypeError | Raised when two different types are combined |
UnboundLocalError | Raised when a local variable is referenced before assignment |
UnicodeError | Raised when a unicode problem occurs |
UnicodeEncodeError | Raised when a unicode encoding problem occurs |
UnicodeDecodeError | Raised when a unicode decoding problem occurs |
UnicodeTranslateError | Raised when a unicode translation problem occurs |
ValueError | Raised when there is a wrong value in a specified data type |
ZeroDivisionError | Raised when the second operator in a division is zero |
❮ Previous
Next ❯
User-Defined Exceptions
Python also allows you to create your own exceptions by deriving classes from the standard built-in exceptions.
Here is an example related to RuntimeError. Here, a class is created that is subclassed from RuntimeError. This is useful when you need to display more specific information when an exception is caught.
In the try block, the user-defined exception is raised and caught in the except block. The variable e is used to create an instance of the class Networkerror.
class Networkerror(RuntimeError): def __init__(self, arg): self.args = arg
So once you defined above class, you can raise the exception as follows −
try: raise Networkerror("Bad hostname") except Networkerror,e: print e.args
Previous Page
Print Page
Next Page
Base classes¶
The following exceptions are used mostly as base classes for other exceptions.
- exception
-
The base class for all built-in exceptions. It is not meant to be directly
inherited by user-defined classes (for that, use ). If
is called on an instance of this class, the representation of
the argument(s) to the instance are returned, or the empty string when
there were no arguments.-
The tuple of arguments given to the exception constructor. Some built-in
exceptions (like ) expect a certain number of arguments and
assign a special meaning to the elements of this tuple, while others are
usually called only with a single string giving an error message.
- (tb)
-
This method sets tb as the new traceback for the exception and returns
the exception object. It is usually used in exception handling code like
this:try ... except SomeException tb = sys.exc_info()[2 raise OtherException(...).with_traceback(tb)
-
- exception
-
All built-in, non-system-exiting exceptions are derived from this class. All
user-defined exceptions should also be derived from this class.
- exception
-
The base class for those built-in exceptions that are raised for various
arithmetic errors: , ,
.
- exception
-
Raised when a related operation cannot be
performed.