One has pretty much control on which information from the traceback to be displayed/logged when catching exceptions.
The code
with open("not_existing_file.txt", 'r') as text:
pass
would produce the following traceback:
Traceback (most recent call last):
File "exception_checks.py", line 19, in <module>
with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'
Print/Log the full traceback
As others already mentioned, you can catch the whole traceback by using the traceback module:
import traceback
try:
with open("not_existing_file.txt", 'r') as text:
pass
except Exception as exception:
traceback.print_exc()
This will produce the following output:
Traceback (most recent call last):
File "exception_checks.py", line 19, in <module>
with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'
You can achieve the same by using logging:
try:
with open("not_existing_file.txt", 'r') as text:
pass
except Exception as exception:
logger.error(exception, exc_info=True)
Output:
__main__: 2020-05-27 12:10:47-ERROR- [Errno 2] No such file or directory: 'not_existing_file.txt'
Traceback (most recent call last):
File "exception_checks.py", line 27, in <module>
with open("not_existing_file.txt", 'r') as text:
FileNotFoundError: [Errno 2] No such file or directory: 'not_existing_file.txt'
Print/log error name/message only
You might not be interested in the whole traceback, but only in the most important information, such as Exception name and Exception message, use:
try:
with open("not_existing_file.txt", 'r') as text:
pass
except Exception as exception:
print("Exception: {}".format(type(exception).__name__))
print("Exception message: {}".format(exception))
Output:
Exception: FileNotFoundError
Exception message: [Errno 2] No such file or directory: 'not_existing_file.txt'
| Введение | |
| Пример с базовым Exception | |
| Два исключения | |
| except Error as e:: Печать текста ошибки | |
| else | |
| finally | |
| raise | |
| Пример 2 | |
| Пример 3 | |
| Исключения, которые не нужно обрабатывать | |
| Список исключений | |
| Разбор примеров: IndexError, ValueError, KeyError | |
| Похожие статьи |
Введение
Если в коде есть ошибка, которую видит интерпретатор поднимается исключение, создается так называемый
Exception Object, выполнение останавливается, в терминале
показывается Traceback.
В английском языке используется словосочетание Raise Exception
Исключение, которое не было предусмотрено разработчиком называется необработанным (Unhandled Exception)
Такое поведение не всегда является оптимальным. Не все ошибки дожны останавливать работу кода.
Возможно, где-то разработчик ожидает появление ошибок и их можно обработать по-другому.
try и except нужны прежде всего для того, чтобы код правильно реагировал на возможные ошибки и продолжал выполняться
там, где появление ошибки некритично.
Исключение, которое предусмотрено в коде называется обработанным (Handled)
Блок try except имеет следующий синтаксис
try:
pass
except Exception:
pass
else:
pass
finally:
pass
В этой статье я создал файл
try_except.py
куда копирую код из примеров.
Пример
Попробуем открыть несуществующий файл и воспользоваться базовым Exception
try:
f = open(‘missing.txt’)
except Exception:
print(‘ERR: File not found’)
python try_except.py
ERR: No missing.txt file found
Ошибка поймана, видно наше сообщение а не Traceback
Проверим, что когда файл существует всё хорошо
try:
f = open(‘existing.txt’)
except Exception:
print(‘ERR: File not found’)
python try_except.py
Пустота означает успех
Два исключения
Если ошибок больше одной нужны дополнительные исключения. Попробуем открыть существующий файл, и после этого
добавить ошибку.
try:
f = open(‘existing.txt’)
x = bad_value
except Exception:
print(‘ERR: File not found’)
python try_except.py
ERR: File not found
Файл открылся, но так как в следующей строке ошибка — в терминале появилось вводящее в заблуждение сообщение.
Проблема не в том, что «File not found» а в том, что bad_value нигде не определёно.
Избежать сбивающих с толку сообщений можно указав тип ожидаемой ошибки. В данном примере это FileNotFoundError
try:
# expected exception
f = open(‘existing.txt’)
# unexpected exception should result in Traceback
x = bad_value
except FileNotFoundError:
print(‘ERR: File not found’)
python try_except.py
Traceback (most recent call last):
File «/home/andrei/python/try_except2.py», line 5, in <module>
x = bad_value
NameError: name ‘bad_value’ is not defined
Вторая ошибка не поймана поэтому показан Traceback
Поймать обе ошибки можно добавив второй Exception
try:
# expected exception should be caught by FileNotFoundError
f = open(‘missing.txt’)
# unexpected exception should be caught by Exception
x = bad_value
except FileNotFoundError:
print(‘ERR: File not found’)
except Exception:
print(‘ERR: Something unexpected went wrong’)
python try_except.py
ERR: File not found
ERR: Something unexpected went wrong
Печать текста ошибки
Вместо своего текста можно выводить текст ошибки. Попробуем с существующим файлом — должна быть одна пойманная ошибка.
try:
# expected exception should be caught by FileNotFoundError
f = open(‘existing.txt’)
# unexpected exception should be caught by Exception
x = bad_value
except FileNotFoundError as e:
print(e)
except Exception as e:
print(e)
python try_except.py
name ‘bad_value’ is not defined
Теперь попытаемся открыть несуществующий файл — должно быть две пойманные ошибки.
try:
# expected exception should be caught by FileNotFoundError
f = open(‘missing.txt’)
# unexpected exception should be caught by Exception
x = bad_value
except FileNotFoundError as e:
print(e)
except Exception as e:
print(e)
python try_except.py
name ‘bad_value’ is not defined
[Errno 2] No such file or directory: ‘missing.txt’
else
Блок else будет выполнен если исключений не будет поймано.
Попробуем открыть существующий файл
existing.txt
в котором есть строка
www.heihei.ru
try:
f = open(‘existing.txt’)
except FileNotFoundError as e:
print(e)
except Exception as e:
print(e)
else:
print(f.read())
f.close()
python try_except.py
www.heihei.ru
Если попробовать открыть несуществующий файл
missing.txt
то исключение обрабатывается, а код из блока else не выполняется.
[Errno 2] No such file or directory: ‘missing.txt’
finally
Блок finally будет выполнен независимо от того, поймано исключение или нет
try:
f = open(‘existing.txt’)
except FileNotFoundError as e:
print(e)
except Exception as e:
print(e)
else:
print(f.read())
f.close()
finally:
print(«Finally!»)
www.heihei.ru
Finally!
А если попытаться открыть несуществующий
missing.txt
[Errno 2] No such file or directory: ‘missing.txt’
Finally!
Когда нужно применять finally:
Рассмотрим скрипт, который вносит какие-то изменения в систему.
Затем он пытается что-то сделать. В конце возвращает
систему в исходное состояние.
Если ошибка случится в середине скрипта — он уже не сможет вернуть систему в исходное состояние.
Но если вынести возврат к исходному состоянию в блок finally он сработает даже при ошибке
в предыдущем блоке.
import os
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
os.mkdir(dir_name)
os.chdir(original_path)
Этот скрипт не вернётся в исходную директорию при ошибке в os.mkdir(dir_name)
А у скрипта ниже такой проблемы нет
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
try:
os.mkdir(dir_name)
finally:
os.chdir(original_path)
Не лишнима будет добавить обработку и вывод исключения
import os
import sys
def make_at(path, dir_name):
original_path = os.getcwd()
os.chdir(path)
try:
os.mkdir(dir_name)
except OSError as e:
print(e, file=sys.stderr)
raise
finally:
os.chdir(original_path)
По умолчанию print() выводит в sys.stdout, но в случае ислючений логичнее выводить в sys.stderr
raise
Можно вызывать исключения вручную в любом месте кода с помощью
raise.
try:
f = open(‘outdated.txt’)
if f.name == ‘outdated.txt’:
raise Exception
except FileNotFoundError as e:
print(e)
except Exception as e:
print(‘File is outdated!’)
else:
print(f.read())
f.close()
finally:
print(«Finally!»)
python try_except.py
File is outdated!
Finally!
raise
можно использовать для перевызова исключения, например, чтобы уйти от использования кодов ошибок.
Для этого достаточно вызвать raise без аргументов — поднимется текущее исключение.
Пример 2
Рассмотрим функцию, которая принимает числа прописью и возвращает цифрами
DIGIT_MAP = {
‘zero’: ‘0’,
‘one’: ‘1’,
‘two’: ‘2’,
‘three’: ‘3’,
‘four’: ‘4’,
‘five’: ‘5’,
‘six’: ‘6’,
‘seven’: ‘7’,
‘eight’: ‘8’,
‘nine’: ‘9’,
}
def convert(s):
number = »
for token in s:
number += DIGIT_MAP[token]
x = int(number)
return x
python
>>> from exc1 import convert
>>> convert(«one three three seven».split())
1337
Теперь передадим аргумент, который не предусмотрен в словаре
>>> convert(«something unseen«.split())
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
File «/home/andrei/python/exc1.py», line 17, in convert
number &plu= DIGIT_MAP[token]
KeyError: ‘something’
KeyError — это тип Exception объекта. Полный список можно изучить в конце статьи.
Исключение прошло следующий путь:
REPL → convert() → DIGIT_MAP(«something») → KeyError
Обработать это исключение можно внеся изменения в функцию convert
convert(s):
try:
number = »
for token in s:
number += DIGIT_MAP[token]
x = int(number)
print(«Conversion succeeded! x = «, x)
except KeyError:
print(«Conversion failed!»)
x = —1
return x
>>> from exc1 import convert
>>> convert(«one nine six one».split())
Conversion succeeded! x = 1961
1961
>>> convert(«something unseen».split())
Conversion failed!
-1
Эта обработка не спасает если передать int вместо итерируемого объекта
>>> convert(2022)
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
File «/home/andrei/python/exc1.py», line 17, in convert
for token in s:
TypeError: ‘int’ object is not iterable
Нужно добавить обработку TypeError
…
except KeyError:
print(«Conversion failed!»)
x = —1
except TypeError:
print(«Conversion failed!»)
x = —1
return x
>>> from exc1 import convert
>>> convert(«2022».split())
Conversion failed!
-1
Избавимся от повторов, удалив принты, объединив два исключения в кортеж и вынесем присваивание значения x
из try блока.
Также добавим
докстринг
с описанием функции.
def convert(s):
«»»Convert a string to an integer.»»»
x = —1
try:
number = »
for token in s:
number += DIGIT_MAP[token]
x = int(number)
except (KeyError, TypeError):
pass
return x
>>> from exc4 import convert
>>> convert(«one nine six one».split())
1961
>>> convert(«bad nine six one».split())
-1
>>> convert(2022)
-1
Ошибки обрабатываются, но без принтов, процесс не очень информативен.
Грамотно показать текст сообщений об ошибках можно импортировав sys и изменив функцию
import sys
DIGIT_MAP = {
‘zero’: ‘0’,
‘one’: ‘1’,
‘two’: ‘2’,
‘three’: ‘3’,
‘four’: ‘4’,
‘five’: ‘5’,
‘six’: ‘6’,
‘seven’: ‘7’,
‘eight’: ‘8’,
‘nine’: ‘9’,
}
def convert(s):
«»»Convert a string to an integer.»»»
try:
number = »
for token in s:
number += DIGIT_MAP[token]
return(int(number))
except (KeyError, TypeError) as e:
print(f«Conversion error: {e!r}», file=sys.stderr)
return —1
>>> from exc1 import convert
>>> convert(2022)
Conversion error: TypeError(«‘int’ object is not iterable»)
-1
>>> convert(«one nine six one».split())
1961
>>> convert(«bad nine six one».split())
Conversion error: KeyError(‘bad’)
Ошибки обрабатываются и их текст виден в терминале.
С помощью
!r
выводится
repr()
ошибки
raise вместо кода ошибки
В предыдущем примере мы полагались на возвращение числа -1 в качестве кода ошибки.
Добавим к коду примера функцию string_log() и поработаем с ней
def string_log(s):
v = convert(s)
return log(v)
>>> from exc1 import string_log
>>> string_log(«one two eight».split())
4.852030263919617
>>> string_log(«bad one two».split())
Conversion error: KeyError(‘bad’)
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
File «/home/andrei/exc1.py», line 32, in string_log
return log(v)
ValueError: math domain error
convert() вернул -1 а string_log попробовал его обработать и не смог.
Можно заменить return -1 на raise. Это считается более правильным подходом в Python
def convert(s):
«»»Convert a string to an integer.»»»
try:
number = »
for token in s:
number += DIGIT_MAP[token]
return(int(number))
except (KeyError, TypeError) as e:
print(f«Conversion error: {e!r}», file=sys.stderr)
raise
>>> from exc7 import string_log
>>> string_log(«one zero».split())
2.302585092994046
>>> string_log(«bad one two».split())
Conversion error: KeyError(‘bad’)
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
File «/home/andrei/exc7.py», line 31, in string_log
v = convert(s)
File «/home/andrei/exc7.py», line 23, in convert
number += DIGIT_MAP[token]
KeyError: ‘bad’
Пример 3
Рассмотрим алгоритм по поиску квадратного корня
def sqrt(x):
«»»Compute square roots using the method
of Heron of Alexandria.
Args:
x: The number for which the square root
is to be computed.
Returns:
The square root of x.
«»»
guess = x
i = 0
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
return guess
def main():
print(sqrt(9))
print(sqrt(2))
if __name__ == ‘__main__’:
main()
python sqrt_ex.py
3.0
1.414213562373095
При попытке вычислить корень от -1 получим ошибку
def main():
print(sqrt(9))
print(sqrt(2))
print(sqrt(-1))
python sqrt_ex.py
3.0
1.414213562373095
Traceback (most recent call last):
File «/home/andrei/sqrt_ex.py», line 26, in <module>
main()
File «/home/andrei/sqrt_ex.py», line 23, in main
print(sqrt(-1))
File «/home/andrei/sqrt_ex.py», line 16, in sqrt
guess = (guess + x / guess) / 2.0
ZeroDivisionError: float division by zero
В строке
guess = (guess + x / guess) / 2.0
Происходит деление на ноль
Обработать можно следующим образом:
def main():
try:
print(sqrt(9))
print(sqrt(2))
print(sqrt(-1))
except ZeroDivisionError:
print(«Cannot compute square root «
«of a negative number.»)
print(«Program execution continues «
«normally here.»)
Обратите внимание на то, что в try помещены все вызовы функции
python sqrt_ex.py
3.0
1.414213562373095
Cannot compute square root of a negative number.
Program execution continues normally here.
Если пытаться делить на ноль несколько раз — поднимется одно исключение и всё что находится в блоке
try после выполняться не будет
def main():
try:
print(sqrt(9))
print(sqrt(-1))
print(sqrt(2))
print(sqrt(-1))
python sqrt_ex.py
3.0
Cannot compute square root of a negative number.
Program execution continues normally here.
Каждую попытку вычислить корень из -1 придётся обрабатывать отдельно. Это кажется неудобным, но
в этом и заключается смысл — каждое место где вы ждёте ислючение нужно помещать в свой
try except блок.
Можно обработать исключение так:
try:
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
except ZeroDivisionError:
raise ValueError()
return guess
def main():
print(sqrt(9))
print(sqrt(-1))
python sqrt_ex.py
3.0
Traceback (most recent call last):
File «/home/andrei/sqrt_ex3.py», line 17, in sqrt
guess = (guess + x / guess) / 2.0
ZeroDivisionError: float division by zero
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File «/home/andrei/sqrt_ex3.py», line 30, in <module>
main()
File «/home/andrei/sqrt_ex3.py», line 25, in main
print(sqrt(-1))
File «/home/andrei/sqrt_ex3.py», line 20, in sqrt
raise ValueError()
ValueError
Гораздо логичнее поднимать исключение сразу при получении аргумента
def sqrt(x):
«»»Compute square roots using the method
of Heron of Alexandria.
Args:
x: The number for which the square root
is to be computed.
Returns:
The square root of x.
Raises:
ValueError: If x is negative
«»»
if x < 0:
raise ValueError(
«Cannot compute square root of «
f«negative number {x}»)
guess = x
i = 0
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
return guess
def main():
print(sqrt(9))
print(sqrt(-1))
print(sqrt(2))
print(sqrt(-1))
if __name__ == ‘__main__’:
main()
python sqrt_ex.py
3.0
Traceback (most recent call last):
File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 35, in <module>
main()
File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 30, in main
print(sqrt(-1))
File «/home/avorotyn/python/lessons/pluralsight/core_python_getting_started/chapter8/sqrt_ex4.py», line 17, in sqrt
raise ValueError(
ValueError: Cannot compute square root of negative number -1
Пока получилось не очень — виден Traceback
Убрать Traceback можно добавив обработку ValueError в вызов функций
import sys
def sqrt(x):
«»»Compute square roots using the method
of Heron of Alexandria.
Args:
x: The number for which the square root
is to be computed.
Returns:
The square root of x.
Raises:
ValueError: If x is negative
«»»
if x < 0:
raise ValueError(
«Cannot compute square root of «
f«negative number {x}»)
guess = x
i = 0
while guess * guess != x and i < 20:
guess = (guess + x / guess) / 2.0
i += 1
return guess
def main():
try:
print(sqrt(9))
print(sqrt(2))
print(sqrt(-1))
print(«This is never printed»)
except ValueError as e:
print(e, file=sys.stderr)
print(«Program execution continues normally here.»)
if __name__ == ‘__main__’:
main()
python sqrt_ex.py
3.0
1.414213562373095
Cannot compute square root of negative number -1
Program execution continues normally here.
Исключения, которые не нужно обрабатывать
IndentationError, SyntaxError, NameError нужно исправлять в коде а не пытаться обработать.
Важно помнить, что использовать обработку исключений для замалчивания ошибок программиста недопустимо.
Список исключений
Список встроенных в Python исключений
Существуют следующие типы объектов Exception
BaseException
+— SystemExit
+— KeyboardInterrupt
+— GeneratorExit
+— Exception
+— StopIteration
+— StopAsyncIteration
+— ArithmeticError
| +— FloatingPointError
| +— OverflowError
| +— ZeroDivisionError
+— AssertionError
+— AttributeError
+— BufferError
+— EOFError
+— ImportError
| +— ModuleNotFoundError
+— LookupError
| +— IndexError
| +— KeyError
+— MemoryError
+— NameError
| +— UnboundLocalError
+— OSError
| +— BlockingIOError
| +— ChildProcessError
| +— ConnectionError
| | +— BrokenPipeError
| | +— ConnectionAbortedError
| | +— ConnectionRefusedError
| | +— ConnectionResetError
| +— FileExistsError
| +— FileNotFoundError
| +— InterruptedError
| +— IsADirectoryError
| +— NotADirectoryError
| +— PermissionError
| +— ProcessLookupError
| +— TimeoutError
+— ReferenceError
+— RuntimeError
| +— NotImplementedError
| +— RecursionError
+— SyntaxError
| +— IndentationError
| +— TabError
+— SystemError
+— TypeError
+— ValueError
| +— UnicodeError
| +— UnicodeDecodeError
| +— UnicodeEncodeError
| +— UnicodeTranslateError
+— Warning
+— DeprecationWarning
+— PendingDeprecationWarning
+— RuntimeWarning
+— SyntaxWarning
+— UserWarning
+— FutureWarning
+— ImportWarning
+— UnicodeWarning
+— BytesWarning
+— EncodingWarning
+— ResourceWarning
IndexError
Объекты, которые поддерживают
протокол
Sequence должны поднимать исключение IndexError при использовании несуществующего индекса.
IndexError как и
KeyError
относится к ошибкам поиска LookupError
Пример
>>> a = [0, 1, 2]
>>> a[3]
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
IndexError: list index out of range
ValueError
ValueError поднимается когда объект правильного типа, но содержит неправильное значение
>>> int(«text»)
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
ValueError: invalid literal for int() with base 10: ‘text’
KeyError
KeyError поднимается когда поиск по ключам не даёт результата
>>> sites = dict(urn=1, heihei=2, eth1=3)
>>> sites[«topbicycle»]
Traceback (most recent call last):
File «<stdin>», line 1, in <module>
KeyError: ‘topbicycle’
TypeError
TypeError поднимается когда для успешного выполнения операции нужен объект
определённого типа, а предоставлен другой тип.
pi = 3.1415
text = «Pi is approximately « + pi
python str_ex.py
Traceback (most recent call last):
File «str_ex.py», line 3, in <module>
text = «Pi is approximately » + pi
TypeError: can only concatenate str (not «float») to str
Пример из статьи
str()
| Python | |
| Интерактивный режим | |
| str: строки | |
| : перенос строки | |
| Списки [] | |
| if, elif, else | |
| Циклы | |
| Функции | |
| Пакеты | |
| *args **kwargs | |
| ООП | |
| enum | |
| Опеределить тип переменной Python | |
| Тестирование с помощью Python | |
| Работа с REST API на Python | |
| Файлы: записать, прочитать, дописать, контекстный менеджер… | |
| Скачать файл по сети | |
| SQLite3: работа с БД | |
| datetime: Дата и время в Python | |
| json.dumps | |
| Selenium + Python | |
| Сложности при работе с Python | |
| DJANGO | |
| Flask | |
| Скрипт для ZPL принтера | |
| socket :Python Sockets | |
| Виртуальное окружение | |
| subprocess: выполнение bash команд из Python | |
| multiprocessing: несколько процессов одновременно | |
| psutil: cистемные ресурсы | |
| sys.argv: аргументы командной строки | |
| PyCharm: IDE | |
| pydantic: валидация данных | |
| paramiko: SSH из Python | |
| enumerate | |
| logging: запись в лог | |
| Обучение программированию на Python |
Содержание:развернуть
- Как устроен механизм исключений
- Как обрабатывать исключения в Python (try except)
-
As — сохраняет ошибку в переменную
-
Finally — выполняется всегда
-
Else — выполняется когда исключение не было вызвано
-
Несколько блоков except
-
Несколько типов исключений в одном блоке except
-
Raise — самостоятельный вызов исключений
-
Как пропустить ошибку
- Исключения в lambda функциях
- 20 типов встроенных исключений в Python
- Как создать свой тип Exception
Программа, написанная на языке Python, останавливается сразу как обнаружит ошибку. Ошибки могут быть (как минимум) двух типов:
- Синтаксические ошибки — возникают, когда написанное выражение не соответствует правилам языка (например, написана лишняя скобка);
- Исключения — возникают во время выполнения программы (например, при делении на ноль).
Синтаксические ошибки исправить просто (если вы используете IDE, он их подсветит). А вот с исключениями всё немного сложнее — не всегда при написании программы можно сказать возникнет или нет в данном месте исключение. Чтобы приложение продолжило работу при возникновении проблем, такие ошибки нужно перехватывать и обрабатывать с помощью блока try/except.
Как устроен механизм исключений
В Python есть встроенные исключения, которые появляются после того как приложение находит ошибку. В этом случае текущий процесс временно приостанавливается и передает ошибку на уровень вверх до тех пор, пока она не будет обработано. Если ошибка не будет обработана, программа прекратит свою работу (а в консоли мы увидим Traceback с подробным описанием ошибки).
💁♂️ Пример: напишем скрипт, в котором функция ожидает число, а мы передаём сроку (это вызовет исключение «TypeError»):
def b(value):
print("-> b")
print(value + 1) # ошибка тут
def a(value):
print("-> a")
b(value)
a("10")
> -> a
> -> b
> Traceback (most recent call last):
> File "test.py", line 11, in <module>
> a("10")
> File "test.py", line 8, in a
> b(value)
> File "test.py", line 3, in b
> print(value + 1)
> TypeError: can only concatenate str (not "int") to str
В данном примере мы запускаем файл «test.py» (через консоль). Вызывается функция «a«, внутри которой вызывается функция «b«. Все работает хорошо до сточки print(value + 1). Тут интерпретатор понимает, что нельзя конкатенировать строку с числом, останавливает выполнение программы и вызывает исключение «TypeError».
Далее ошибка передается по цепочке в обратном направлении: «b» → «a» → «test.py«. Так как в данном примере мы не позаботились обработать эту ошибку, вся информация по ошибке отобразится в консоли в виде Traceback.
Traceback (трассировка) — это отчёт, содержащий вызовы функций, выполненные в определенный момент. Трассировка помогает узнать, что пошло не так и в каком месте это произошло.
Traceback лучше читать снизу вверх ↑
В нашем примере Traceback содержится следующую информацию (читаем снизу вверх):
TypeError— тип ошибки (означает, что операция не может быть выполнена с переменной этого типа);can only concatenate str (not "int") to str— подробное описание ошибки (конкатенировать можно только строку со строкой);- Стек вызова функций (1-я линия — место, 2-я линия — код). В нашем примере видно, что в файле «test.py» на 11-й линии был вызов функции «a» со строковым аргументом «10». Далее был вызов функции «b».
print(value + 1)это последнее, что было выполнено — тут и произошла ошибка. most recent call last— означает, что самый последний вызов будет отображаться последним в стеке (в нашем примере последним выполнилсяprint(value + 1)).
В Python ошибку можно перехватить, обработать, и продолжить выполнение программы — для этого используется конструкция try ... except ....
Как обрабатывать исключения в Python (try except)
В Python исключения обрабатываются с помощью блоков try/except. Для этого операция, которая может вызвать исключение, помещается внутрь блока try. А код, который должен быть выполнен при возникновении ошибки, находится внутри except.
Например, вот как можно обработать ошибку деления на ноль:
try:
a = 7 / 0
except:
print('Ошибка! Деление на 0')
Здесь в блоке try находится код a = 7 / 0 — при попытке его выполнить возникнет исключение и выполнится код в блоке except (то есть будет выведено сообщение «Ошибка! Деление на 0»). После этого программа продолжит свое выполнение.
💭 PEP 8 рекомендует, по возможности, указывать конкретный тип исключения после ключевого слова except (чтобы перехватывать и обрабатывать конкретные исключения):
try:
a = 7 / 0
except ZeroDivisionError:
print('Ошибка! Деление на 0')
Однако если вы хотите перехватывать все исключения, которые сигнализируют об ошибках программы, используйте тип исключения Exception:
try:
a = 7 / 0
except Exception:
print('Любая ошибка!')
As — сохраняет ошибку в переменную
Перехваченная ошибка представляет собой объект класса, унаследованного от «BaseException». С помощью ключевого слова as можно записать этот объект в переменную, чтобы обратиться к нему внутри блока except:
try:
file = open('ok123.txt', 'r')
except FileNotFoundError as e:
print(e)
> [Errno 2] No such file or directory: 'ok123.txt'
В примере выше мы обращаемся к объекту класса «FileNotFoundError» (при выводе на экран через print отобразится строка с полным описанием ошибки).
У каждого объекта есть поля, к которым можно обращаться (например если нужно логировать ошибку в собственном формате):
import datetime
now = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S")
try:
file = open('ok123.txt', 'r')
except FileNotFoundError as e:
print(f"{now} [FileNotFoundError]: {e.strerror}, filename: {e.filename}")
> 20-11-2021 18:42:01 [FileNotFoundError]: No such file or directory, filename: ok123.txt
Finally — выполняется всегда
При обработке исключений можно после блока try использовать блок finally. Он похож на блок except, но команды, написанные внутри него, выполняются обязательно. Если в блоке try не возникнет исключения, то блок finally выполнится так же, как и при наличии ошибки, и программа возобновит свою работу.
Обычно try/except используется для перехвата исключений и восстановления нормальной работы приложения, а try/finally для того, чтобы гарантировать выполнение определенных действий (например, для закрытия внешних ресурсов, таких как ранее открытые файлы).
В следующем примере откроем файл и обратимся к несуществующей строке:
file = open('ok.txt', 'r')
try:
lines = file.readlines()
print(lines[5])
finally:
file.close()
if file.closed:
print("файл закрыт!")
> файл закрыт!
> Traceback (most recent call last):
> File "test.py", line 5, in <module>
> print(lines[5])
> IndexError: list index out of range
Даже после исключения «IndexError», сработал код в секции finally, который закрыл файл.
p.s. данный пример создан для демонстрации, в реальном проекте для работы с файлами лучше использовать менеджер контекста with.
Также можно использовать одновременно три блока try/except/finally. В этом случае:
- в
try— код, который может вызвать исключения; - в
except— код, который должен выполниться при возникновении исключения; - в
finally— код, который должен выполниться в любом случае.
def sum(a, b):
res = 0
try:
res = a + b
except TypeError:
res = int(a) + int(b)
finally:
print(f"a = {a}, b = {b}, res = {res}")
sum(1, "2")
> a = 1, b = 2, res = 3
Else — выполняется когда исключение не было вызвано
Иногда нужно выполнить определенные действия, когда код внутри блока try не вызвал исключения. Для этого используется блок else.
Допустим нужно вывести результат деления двух чисел и обработать исключения в случае попытки деления на ноль:
b = int(input('b = '))
c = int(input('c = '))
try:
a = b / c
except ZeroDivisionError:
print('Ошибка! Деление на 0')
else:
print(f"a = {a}")
> b = 10
> c = 1
> a = 10.0
В этом случае, если пользователь присвоит переменной «с» ноль, то появится исключение и будет выведено сообщение «‘Ошибка! Деление на 0′», а код внутри блока else выполняться не будет. Если ошибки не будет, то на экране появятся результаты деления.
Несколько блоков except
В программе может возникнуть несколько исключений, например:
- Ошибка преобразования введенных значений к типу
float(«ValueError»); - Деление на ноль («ZeroDivisionError»).
В Python, чтобы по-разному обрабатывать разные типы ошибок, создают несколько блоков except:
try:
b = float(input('b = '))
c = float(input('c = '))
a = b / c
except ZeroDivisionError:
print('Ошибка! Деление на 0')
except ValueError:
print('Число введено неверно')
else:
print(f"a = {a}")
> b = 10
> c = 0
> Ошибка! Деление на 0
> b = 10
> c = питон
> Число введено неверно
Теперь для разных типов ошибок есть свой обработчик.
Несколько типов исключений в одном блоке except
Можно также обрабатывать в одном блоке except сразу несколько исключений. Для этого они записываются в круглых скобках, через запятую сразу после ключевого слова except. Чтобы обработать сообщения «ZeroDivisionError» и «ValueError» в одном блоке записываем их следующим образом:
try:
b = float(input('b = '))
c = float(input('c = '))
a = b / c
except (ZeroDivisionError, ValueError) as er:
print(er)
else:
print('a = ', a)
При этом переменной er присваивается объект того исключения, которое было вызвано. В результате на экран выводятся сведения о конкретной ошибке.
Raise — самостоятельный вызов исключений
Исключения можно генерировать самостоятельно — для этого нужно запустить оператор raise.
min = 100
if min > 10:
raise Exception('min must be less than 10')
> Traceback (most recent call last):
> File "test.py", line 3, in <module>
> raise Exception('min value must be less than 10')
> Exception: min must be less than 10
Перехватываются такие сообщения точно так же, как и остальные:
min = 100
try:
if min > 10:
raise Exception('min must be less than 10')
except Exception:
print('Моя ошибка')
> Моя ошибка
Кроме того, ошибку можно обработать в блоке except и пробросить дальше (вверх по стеку) с помощью raise:
min = 100
try:
if min > 10:
raise Exception('min must be less than 10')
except Exception:
print('Моя ошибка')
raise
> Моя ошибка
> Traceback (most recent call last):
> File "test.py", line 5, in <module>
> raise Exception('min must be less than 10')
> Exception: min must be less than 10
Как пропустить ошибку
Иногда ошибку обрабатывать не нужно. В этом случае ее можно пропустить с помощью pass:
try:
a = 7 / 0
except ZeroDivisionError:
pass
Исключения в lambda функциях
Обрабатывать исключения внутри lambda функций нельзя (так как lambda записывается в виде одного выражения). В этом случае нужно использовать именованную функцию.
20 типов встроенных исключений в Python
Иерархия классов для встроенных исключений в Python выглядит так:
BaseException
SystemExit
KeyboardInterrupt
GeneratorExit
Exception
ArithmeticError
AssertionError
...
...
...
ValueError
Warning
Все исключения в Python наследуются от базового BaseException:
SystemExit— системное исключение, вызываемое функциейsys.exit()во время выхода из приложения;KeyboardInterrupt— возникает при завершении программы пользователем (чаще всего при нажатии клавиш Ctrl+C);GeneratorExit— вызывается методомcloseобъектаgenerator;Exception— исключения, которые можно и нужно обрабатывать (предыдущие были системными и их трогать не рекомендуется).
От Exception наследуются:
1 StopIteration — вызывается функцией next в том случае если в итераторе закончились элементы;
2 ArithmeticError — ошибки, возникающие при вычислении, бывают следующие типы:
FloatingPointError— ошибки при выполнении вычислений с плавающей точкой (встречаются редко);OverflowError— результат вычислений большой для текущего представления (не появляется при операциях с целыми числами, но может появиться в некоторых других случаях);ZeroDivisionError— возникает при попытке деления на ноль.
3 AssertionError — выражение, используемое в функции assert неверно;
4 AttributeError — у объекта отсутствует нужный атрибут;
5 BufferError — операция, для выполнения которой требуется буфер, не выполнена;
6 EOFError — ошибка чтения из файла;
7 ImportError — ошибка импортирования модуля;
8 LookupError — неверный индекс, делится на два типа:
IndexError— индекс выходит за пределы диапазона элементов;KeyError— индекс отсутствует (для словарей, множеств и подобных объектов);
9 MemoryError — память переполнена;
10 NameError — отсутствует переменная с данным именем;
11 OSError — исключения, генерируемые операционной системой:
ChildProcessError— ошибки, связанные с выполнением дочернего процесса;ConnectionError— исключения связанные с подключениями (BrokenPipeError, ConnectionResetError, ConnectionRefusedError, ConnectionAbortedError);FileExistsError— возникает при попытке создания уже существующего файла или директории;FileNotFoundError— генерируется при попытке обращения к несуществующему файлу;InterruptedError— возникает в том случае если системный вызов был прерван внешним сигналом;IsADirectoryError— программа обращается к файлу, а это директория;NotADirectoryError— приложение обращается к директории, а это файл;PermissionError— прав доступа недостаточно для выполнения операции;ProcessLookupError— процесс, к которому обращается приложение не запущен или отсутствует;TimeoutError— время ожидания истекло;
12 ReferenceError — попытка доступа к объекту с помощью слабой ссылки, когда объект не существует;
13 RuntimeError — генерируется в случае, когда исключение не может быть классифицировано или не подпадает под любую другую категорию;
14 NotImplementedError — абстрактные методы класса нуждаются в переопределении;
15 SyntaxError — ошибка синтаксиса;
16 SystemError — сигнализирует о внутренне ошибке;
17 TypeError — операция не может быть выполнена с переменной этого типа;
18 ValueError — возникает когда в функцию передается объект правильного типа, но имеющий некорректное значение;
19 UnicodeError — исключение связанное с кодирование текста в unicode, бывает трех видов:
UnicodeEncodeError— ошибка кодирования;UnicodeDecodeError— ошибка декодирования;UnicodeTranslateError— ошибка переводаunicode.
20 Warning — предупреждение, некритическая ошибка.
💭 Посмотреть всю цепочку наследования конкретного типа исключения можно с помощью модуля inspect:
import inspect
print(inspect.getmro(TimeoutError))
> (<class 'TimeoutError'>, <class 'OSError'>, <class 'Exception'>, <class 'BaseException'>, <class 'object'>)
📄 Подробное описание всех классов встроенных исключений в Python смотрите в официальной документации.
Как создать свой тип Exception
В Python можно создавать свои исключения. При этом есть одно обязательное условие: они должны быть потомками класса Exception:
class MyError(Exception):
def __init__(self, text):
self.txt = text
try:
raise MyError('Моя ошибка')
except MyError as er:
print(er)
> Моя ошибка
С помощью try/except контролируются и обрабатываются ошибки в приложении. Это особенно актуально для критически важных частей программы, где любые «падения» недопустимы (или могут привести к негативным последствиям). Например, если программа работает как «демон», падение приведет к полной остановке её работы. Или, например, при временном сбое соединения с базой данных, программа также прервёт своё выполнение (хотя можно было отловить ошибку и попробовать соединиться в БД заново).
Вместе с try/except можно использовать дополнительные блоки. Если использовать все блоки описанные в статье, то код будет выглядеть так:
try:
# попробуем что-то сделать
except (ZeroDivisionError, ValueError) as e:
# обрабатываем исключения типа ZeroDivisionError или ValueError
except Exception as e:
# исключение не ZeroDivisionError и не ValueError
# поэтому обрабатываем исключение общего типа (унаследованное от Exception)
# сюда не сходят исключения типа GeneratorExit, KeyboardInterrupt, SystemExit
else:
# этот блок выполняется, если нет исключений
# если в этом блоке сделать return, он не будет вызван, пока не выполнился блок finally
finally:
# этот блок выполняется всегда, даже если нет исключений else будет проигнорирован
# если в этом блоке сделать return, то return в блоке
Подробнее о работе с исключениями в Python можно ознакомиться в официальной документации.
Применение try except Python 3 — наиболее распространенный способ обработки ошибок. В этой статье мы познакомимся с лучшими практиками использования try except Python 3.
Используя блок try, можно перехватить исключение и обработать ошибку внутри блока except. Всякий раз, когда код дает сбой внутри блока try, выполнение программы останавливается, и управление передается блоку исключений.
- Для чего используются условия Try-Except Python / Try-Except-else?
- Выведение исключений
- Для чего используются исключения?
- Советы по использованию Try Except Python 3, Try-Except-Else и многое другое
- Как обрабатывать произвольное исключение
- Перехват нескольких исключений в одном блоке except
- Обработка нескольких исключений в одном блоке except
- Повторное выведение исключений в Python
- Когда использовать условие else
- Использование блока [finally]
- Используйте ключевое слово as для перехвата конкретных типов исключений
- Лучшие практики вывода исключений
- Как пропустить ошибки и продолжить выполнение кода
- Как использовать Try-Except в Python
С помощью try-except и try-except-else можно избежать многих проблем, которые могут возникнуть. Например, код Python, использующий стиль LBYL (Look before you leap), может привести к зацикливанию условий. В подобном случае поможет try-except.
Также бывают случаи, когда правильность выполнения кода зависит от актуальности данных. Например, код, вызывающий os.path.exists или Queue.full, может завершиться неудачно. Эти функции могут возвращать данные, которые устаревают к моменту их использования. Поэтому лучше использовать try-except-else.
В Python можно выводить исключение каждый раз, когда это необходимо. Это можно сделать, вызвав из кода [raise Exception (‘Test error!’)]. После чего исключение остановит текущее выполнение и перейдет дальше по стеку вызовов до тех пор, пока исключение не будет обработано.
Исключения также используются для управления ошибками, которые возникают в циклах, при работе с базой данных, доступе к сети и т.д.
Обработка исключений — это искусство, которое помогает в написании надежного и качественного кода.

Как в Python лучше всего использовать Try-Except
Иногда может понадобиться способ для обработки и вывода сообщения об ошибке. Это можно сделать с помощью исключений Python. Во время тестирования вы можете разместить код внутри блока try.
try:
#ваш код
except Exception as ex:
print(ex)
Можно перехватить несколько исключений в одном блоке except.
except (Exception1, Exception2) as e:
pass
Обратите внимание, что в Python 2.6 / 2.7 нужно отделить исключения от переменной запятой. Но этого нельзя делать в Python 3. Вместо этого необходимо использовать ключевое слово [as].
Существует множество способов обработки сразу нескольких исключений. Первый из них требует размещения всех исключений, которые могут возникнуть. Смотрите приведенный ниже код:
try:
file = open('input-file', 'open mode')
except EOFError as ex:
print("Caught the EOF error.")
raise ex
except IOError as e:
print("Caught the I/O error.")
raise ex
Последний метод — использовать исключение без упоминания какого-либо атрибута исключения.
try:
file = open('input-file', 'open mode')
except:
# In case of any unhandled error, throw it away
raise
Последний вариант может быть полезен, если у вас нет информации об исключении, которое может возникнуть.
Однажды выведенные исключения продолжают обрабатываться в вызывающих их методах до тех пор, пока они не будут обработаны. Но можно добавить условие except, которое содержит только вызов [raise] без каких-либо аргументов. Это приведет к повторному исключению.
Смотрите приведенный ниже код.
try:
# Намеренное выведение исключения.
raise Exception('I learn Python!')
except:
print("Entered in except.")
# Повторное выведение исключения.
raise
Вывод:
Entered in except. Traceback (most recent call last): File "python", line 3, in <module> Exception: I learn Python!
Используйте условие else после блока try-except. Оно будет выполняться в том случае, если исключение не будет выдано. Оператор else всегда должен предшествовать блокам except .
В блоках else можно добавить код, который необходимо запустить, если ошибок не возникло.
В приведенном ниже примере видно, что цикл while работает бесконечно. Код запрашивает значение у пользователя, а затем анализирует его с помощью встроенной функции [int()]. Если пользователь вводит нулевое значение, блок except будет заблокирован. В противном случае код будет проходить через блок else.
while True:
# Введете с консоли целое число.
x = int(input())
# Разделите 1 на x, чтобы протестировать ошибку
try:
result = 1 / x
except:
print("Error case")
exit(0)
else:
print("Pass case")
exit(1)
Если есть код, который должен выполняться во всех случаях, разместите его внутри блока [finally]. Python всегда будет запускать эти инструкции. Это самый распространенный способ выполнения задач очистки. Вы также можете проверить это.
Ошибка перехватывается условием try. После того, как будет выполнен код в блоке except, выполняется инструкции в [finally].
Смотрите приведенный ниже код.
try:
# Намеренно выводим ошибку.
x = 1 / 0
except:
# Условие Except:
print("Error occurred")
finally:
# Условие Finally:
print("The [finally clause] is hit")
Вывод:
Error occurred The [finally clause] is hit
С помощью <identifier> можно создать объект исключения. В приведенном ниже примере мы создаем объект IOError, а затем используем его внутри условия.
try:
# Намеренно выводим ошибку.
f = open("no-file")
except IOError as err:
# Создаем экземпляр IOError для учета.
print("Error:", err)
print("Code:", err.errno)
Вывод:
('Error:', IOError(2, 'No such file or directory'))
('Code:', 2)
Избегайте создания общих исключений, иначе конкретные exception также будут перехватываться. Лучшей практикой является отображение конкретного исключения, близкого к возникшей проблеме.
Не рекомендуется:
def bad_exception():
try:
raise ValueError('Intentional - do not want this to get caught')
raise Exception('Exception to be handled')
except Exception as error:
print('Inside the except block: ' + repr(error))
bad_exception()
Вывод:
Inside the except block: ValueError('Intentional - do not want this to get caught',)
Рекомендуется:
В приведенном ниже примере перехватывается конкретный тип исключения, а не общий. Мы также используем параметр args для вывода некорректных аргументов, если они есть. Рассмотрим этот пример.
try:
raise ValueError('Testing exceptions: The input is in incorrect order', 'one', 'two', 'four')
except ValueError as err:
print(err.args)
Вывод:
('Testing exceptions: The input is in incorrect order', 'one', 'two', 'four')
Лучше не применять данную практику. Но если это нужно, то используйте следующий пример.
try:
assert False
except AssertionError:
pass
print('Welcome to Prometheus!!!')
Вывод:
Рассмотрим наиболее распространенные исключения в Python с примерами.
Распространенные ошибки исключений:
- IOError–возникает, если файл не открывается.
- ImportError — если модуль python не может быть загружен или размещен.
- ValueError — возникает, если функция получает аргумент корректного типа, но с некорректным значением.
- KeyboardInterrupt — когда пользователь прерывает выполнение кода нажатием на Delили Ctrl-C.
- EOFError — когда функции input() / raw_input()достигают конца файла (EOF), но без чтения каких-либо данных.
Примеры распространенных исключений
except IOError:
print('Error occurred while opening the file.')
except ValueError:
print('Non-numeric input detected.')
except ImportError:
print('Unable to locate the module.')
except EOFError:
print('Identified EOF error.')
except KeyboardInterrupt:
print('Wrong keyboard input.')
except:
print('An error occurred.')
В процессе программирования ошибки неизбежны. Но их можно обработать, используя конструкции try-except или try-except-else, try-except-finally.
Обработка исключений в Python 3 является мощным механизмом по управлению программой в особых ситуациях. Он позволяет избежать ее аварийного завершения вследствие внезапных и непредвиденных ошибок. Такая возможность реализована в языке программирования Python при помощи специальных синтаксических конструкций, позволяющих отлавливать, а затем обрабатывать исключения для того, чтобы программа всегда выполняла заданный алгоритм.
Что такое исключения?
Разработка программы на любом языке довольно часто бывает связана с возникновением различного рода ошибок, препятствующих получению желаемого результата. Как правило, не все они приводят к моментальному завершению программы: некоторые ошибки можно ликвидировать еще на этапе компиляции, другие же способны оставаться незамеченными достаточно долгое время, а третьи и вовсе не зависят от программиста и возникают лишь в определенных ситуациях.
На сегодняшний день принято выделять такие типы ошибок:
- Синтаксические – возникают из-за синтаксических погрешностей кода;
- Логические – проявляются вследствие логических неточностей в алгоритме;
- Исключения – вызваны некорректными действиями пользователя или системы.
Синтаксические ошибки являются следствием несоблюдения общепринятых норм языка, например, пропуска круглой скобки в предполагаемом месте или некорректного написания имени функции. Такие погрешности успешно отлавливаются компилятором, который сразу же сообщает пользователю о проблеме в написанном коде. Следующий пример показывает, что будет, если пропустить символ двойных кавычек при создании строкового литерала:
print("Hello World!)
После попытки запуска выдастся текст ошибки:
File "main.py", line 1
print("Hello World!)
^
SyntaxError: EOL while scanning string literal
Логические ошибки считаются более сложными в выявлении, поскольку не отлавливаются ни на этапе компиляции, ни во время выполнения готовой программы. Обычно они вызваны определенными недостатками в логике написанного алгоритма, из-за чего пользователь не получает желаемого результата. Ниже показана работа функции, которая должна вычислять среднее значение двух чисел, однако она этого не делает из-за неправильной формулы:
def avg(a, b):
return a + b / 2
print(avg(10, 20))
20
Исключения представляют собой еще один вид ошибок, который проявляется в зависимости от наличия обстоятельств, меняющих ход выполнения программы. Примером этому вполне может быть ввод некорректного значения либо отсутствие нужного файла. Как правило, все доступные виды исключений становятся видимыми во время выполнения программы. Далее продемонстрирован пример, показывающий невозможность операции деления на ноль:
print(10 / 0)
После попытки запуска будет выведено:
Traceback (most recent call last): File "main.py", line 1, in <module> print(10 / 0) ZeroDivisionError: division by zero
Как можно заметить из результатов выполнения программы, деление на ноль провоцирует исключительную ситуацию, которая приводит к аварийному завершению работы и выводу ошибки на экран. В данном случае отображается файл, а также номер строки кода, где было выброшено исключение ZeroDivisionError. Ниже приводится краткое описание проблемы.
Перехват исключений
Для того, чтобы исключение не приводило к внезапному завершению программы, его стоит обработать. Для этого есть специальный механизм, предотвращающего все непредвиденные ситуации. Это поможет избежать сбоев в работе написанного алгоритма за счет расширения его возможностей, позволяющих действовать согласно новым обстоятельствам. Но сначала попробуем запустить программу, которая попытается открыть обычный текстовый файл:
print("Program started")
print("Opening file...")
f = open("data.txt")
print("Program finished")
После запуск будет выведено:
Program started
Opening file...
Traceback (most recent call last):
File "main.py", line 3, in <module>
f = open("data.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'data.txt'
Так как файла с таким именем на жестком диске не обнаружено, программа сгенерировала исключение FileNotFoundError, сообщающее о проблеме с вводом/выводом. Последняя строка кода, в которой обозначается завершение программы, не была отображена на экране. Это значит, что не все операции, предусмотренные алгоритмом, были выполнены из-за проявившегося исключения.
Рассмотрим пример в Python конструкции try-except. Она позволяет обработать исключительную ситуацию без необходимости завершения уже работающей программы:
print("Program started")
try:
print("Opening file...")
f = open("data.txt")
except:
print("File not found!")
print("Program finished")
Program started
Opening file...
File not found!
Program finished
Как видно из кода выше, блок try содержит опасный код, способный привести к ошибке (отсутствие нужного файла), а блок except включает в себя инструкции, которые следует выполнить в случае возникнувшей проблемы. Теперь если требуемый файл не был найден, программа не станет завершаться, о чем свидетельствует последний вывод функции print.
Несколько блоков except
Блоков except может быть несколько, в зависимости от того, какой тип исключения нужно обработать. Как правило, сначала обрабатываются более частные случаи, а затем общие:
print("Program started")
try:
print("Opening file...")
f = open("data.txt")
except FileNotFoundError:
print("File not found!")
except Exception:
print("Something gone wrong!")
print("Program finished")
Program started
Opening file...
File not found!
Program finished
Вложенные блоки и else
Блоки try-except могут быть вложенными для более гибкого управления исключениями. В следующем примере демонстрируется попытка открыть текстовый файл и записать в него некую строку. Для каждой цели используется отдельный блок try.
Также в данном примере используется конструкция else, которая выполняется в случае, если в коде не произошло исключений.
В данном случае — else сработает при успешной операции write. По умолчанию файл открывается на чтение в текстовом режиме. Поэтому при открытии файла будем использовать режим «w». В этом режиме файл открывается на запись. Если файла не было — создается новый, если был — перезаписывается.
print("Program started")
try:
print("Opening file...")
f = open("data.txt", "w")
try:
print("Writing to file...")
f.write("Hello World!")
except Exception:
print("Something gone wrong!")
else:
print("Success!")
except FileNotFoundError:
print("File not found!")
print("Program finished")
Program started
Opening file...
Writing to file...
Success!
Program finished
finally
Бывают ситуации, когда некие важные действия необходимо совершить вне зависимости от того, было вызвано исключение или нет. Для этого используется блок finally, содержащий набор инструкций, которые нужно выполнить в любом случае. Следующий пример улучшает работу предыдущей программы, добавляя в нее возможность закрывать текстовый файл:
print("Program started")
try:
print("Opening file...")
f = open("data.txt", "w")
try:
print("Writing to file...")
f.write("Hello World!")
except Exception:
print("Something gone wrong!")
else:
print("Success!")
finally:
print("Closing file...")
f.close()
except FileNotFoundError:
print("File not found!")
print("Program finished")
Program started
Opening file...
Writing to file...
Success!
Closing file...
Program finished
Иногда такой подход к работе с текстовыми файлами может показаться слишком сложным, так как код, который его реализует, выглядит громоздким. Специально для этого существует конструкция with/as, позволяющая автоматизировать некоторые методы, такие как закрытие файла у соответствующего объекта. Таким образом, сокращается длина написанного кода:
print("Program started")
try:
print("Writing to file...")
with open("data.txt", "w") as f:
f.write("Hello World!")
except Exception:
print("Something gone wrong!")
print("Program finished")
Program started
Writing to file...
Program finished
Как и во всех предыдущих случаях, программа, которая способна правильно обработать все возникающие типы исключений, всегда завершается естественным образом, без прерываний заданного алгоритма. Это значительно повышает комфорт и безопасность ее использования.
Управление исключениями
Python позволяет создавать пользовательские исключения. Так же рассмотрим логирование программы.
Пользовательские исключения
Как правило, исключения автоматически вызываются в нужных ситуациях, однако в Python присутствует возможность запускать их самостоятельно. Для этого применяется ключевое слово raise. Следом за ним необходимо создать новый объект типа Exception, который потом можно обработать при помощи привычных конструкций try-except, как в данном примере:
print("Program started")
try:
raise Exception("User Exception!")
except Exception as e:
print(str(e))
print("Program finished")
Program started
User Exception!
Program finished
Чтобы описать собственный тип исключения, нужно создать новый класс, унаследованный от базового типа Exception. Это позволит запускать особые виды исключений в ситуациях, когда поведение пользователя не соответствует алгоритму программы. В конструкторе Exception указываем текст исключения. После того, как оно сработало и было перехвачено, можно его получить с помощью str.
В следующем коде показан процесс генерации исключения NegativeAge, которое не позволяет пользователю ввести отрицательный возраст. Таким образом, экран выдает соответствующую ошибку:
class NegativeAge(Exception):
pass
print("Program started")
try:
age = int(input("Enter your age: "))
if age < 0:
raise NegativeAge("Exception: Negative age!")
print("Success!")
except NegativeAge as e:
print(e)
print("Program finished")
Program started
Enter your age: -18
Exception: Negative age!
Program finished
Запись в лог
Для вывода специальных сообщений, не влияющих на функционирование программы, в Python применяется библиотека логов. Чтобы воспользоваться ею, необходимо выполнить импорт в верхней части файла. Существует несколько типов логов, отобразить которые поможет команда, определенная во второй строке кода в следующем примере программы:
import logging
logging.basicConfig(level = logging.DEBUG)
logging.debug("Debug message!")
logging.info("Info message!")
logging.warning("Warning message!")
logging.error("Error message!")
logging.critical("Critical message!")
DEBUG:root:Debug message!
INFO:root:Info message!
WARNING:root:Warning message!
ERROR:root:Error message!
CRITICAL:root:Critical message!
Как видно из результатов выполнения программы, пользователю доступны разные типы сообщений, такие как предупреждение, информация или ошибка. Обычно они применяются при разработке программного обеспечения, чтобы не выводить лишний текст в консоль.
С помощью logging на Python можно записывать в лог и исключения. Обычно лог пишется в файл, зададим его как log.txt. Уровень INFO указывает, что сообщения уровней ниже (в данном случае debug) не будут отражаться в логе. Python позволяет в try-except получить текст ошибки, который и запишем:
import logging
logging.basicConfig(filename="log.txt", level = logging.INFO)
try:
print(10 / 0)
except Exception as e:
logging.error(str(e))
В log .txt будет добавлена строка сообщения о типе сработавшего исключения «ERROR:root:division by zero».
Иерархия исключений
В языке программирования Python присутствует строгая иерархия исключений. Вершиной является BaseException, включающий в себя все существующие разновидности исключений:
- SystemExit – возникает при выходе из программы с помощью sys.exit;
- KeyboardInterrupt – указывает на прерывание программы пользователем;
- GeneratorExit – появляется при вызове метода close для объекта generator;
- Exception – представляет совокупность обычных несистемных исключений.
Перечень несистемных исключений, которые содержит в себе класс Exception приведены в следующей таблице. Все они актуальны для последней на данный момент версии Python 3.
| Название | Характеристика |
| ArithmeticError | Порождается арифметическими ошибками (операции с плавающей точкой, переполнение числовой переменной, деление на ноль) |
| AssertionError | Возникает при ложном выражении в функции assert |
| AttributeError | Появляется в случаях, когда нужный атрибут объекта отсутствует |
| BufferError | Указывает на невозможность выполнения буферной операции |
| EOFError | Проявляется, когда функция не смогла прочитать конец файла |
| ImportError | Сообщает о неудачном импорте модуля либо атрибута |
| LookupError | Информирует про недействительный индекс или ключ в массиве |
| MemoryError | Возникает в ситуации, когда доступной памяти недостаточно |
| NameError | Указывает на ошибку при поиске переменной с нужным именем |
| NotImplementedError | Предупреждает о том, что абстрактные методы класса должны быть обязательно переопределены в классах-наследниках |
| OSError | Включает в себя системные ошибки (отсутствие доступа к нужному файлу или директории, проблемы с поиском процессов) |
| ReferenceError | Порождается попыткой доступа к атрибуту со слабой ссылкой |
| RuntimeError | Сообщает об исключении, которое не классифицируется |
| StopIteration | Возникает во время работы функции next при отсутствии элементов |
| SyntaxError | Представляет собой совокупность синтаксических ошибок |
| SystemError | Порождается внутренними ошибками системы |
| TypeError | Указывает на то, что операция не может быть выполнена с объектом |
| UnicodeError | Сообщает о неправильной кодировке символов в программе |
| ValueError | Возникает при получении некорректного значения для переменной |
| Warning | Обозначает предупреждение |
Заключение
Исключения являются самостоятельным типом данных, при помощи которого программа сообщает пользователю о различных ошибках. Обработка исключений позволяет менять сценарий выполнения программы с учетом обстоятельств, так или иначе блокирующих ее нормальную работу. Для удобного управления исключениями в языке программирования Python предусмотрены специальные синтаксические конструкции. Кроме того, в нем есть большая библиотека готовых исключений, а также возможность создавать собственные.
В этом руководстве мы расскажем, как обрабатывать исключения в Python с помощью try и except. Рассмотрим общий синтаксис и простые примеры, обсудим, что может пойти не так, и предложим меры по исправлению положения.
Зачастую разработчик может предугадать возникновение ошибок при работе даже синтаксически и логически правильной программы. Эти ошибки могут быть вызваны неверными входными данными или некоторыми предсказуемыми несоответствиями.
Для обработки большей части этих ошибок как исключений в Python есть блоки try и except.
Для начала разберем синтаксис операторов try и except в Python. Общий шаблон представлен ниже:
try:
# В этом блоке могут быть ошибки
except <error type>:
# Сделай это для обработки исключения;
# выполняется, если блок try выбрасывает ошибку
else:
# Сделай это, если блок try выполняется успешно, без ошибок
finally:
# Этот блок выполняется всегда
Давайте посмотрим, для чего используются разные блоки.
Блок try
Блок try — это блок кода, который вы хотите попробовать выполнить. Однако во время выполнения из-за какого-нибудь исключения могут возникнуть ошибки. Поэтому этот блок может не работать должным образом.
Блок except
Блок except запускается, когда блок try не срабатывает из-за исключения. Инструкции в этом блоке часто дают некоторый контекст того, что пошло не так внутри блока try.
Если собираетесь перехватить ошибку как исключение, в блоке except нужно обязательно указать тип этой ошибки. В приведенном выше сниппете место для указания типа ошибки обозначено плейсхолдером <error type> .
except можно использовать и без указания типа ошибки. Но лучше так не делать. При таком подходе не учитывается, что возникающие ошибки могут быть разных типов. То есть вы будете знать, что что-то пошло не так, но что именно произошло, какая была ошибка — вам будет не известно.
При попытке выполнить код внутри блока try также существует вероятность возникновения нескольких ошибок.
Например, вы можете попытаться обратиться к элементу списка по индексу, выходящему за пределы допустимого диапазона, использовать неправильный ключ словаря и попробовать открыть несуществующий файл – и все это внутри одного блока try.
В результате вы можете столкнуться с IndexError, KeyError и FileNotFoundError. В таком случае нужно добавить столько блоков except, сколько ошибок ожидается – по одному для каждого типа ошибки.
Блок else
Блок else запускается только в том случае, если блок try выполняется без ошибок. Это может быть полезно, когда нужно выполнить ещё какие-то действия после успешного выполнения блока try. Например, после успешного открытия файла вы можете прочитать его содержимое.
Блок finally
Блок finally выполняется всегда, независимо от того, что происходит в других блоках. Это полезно, когда вы хотите освободить ресурсы после выполнения определенного блока кода.
Примечание: блоки else и finally не являются обязательными. В большинстве случаев вы можете использовать только блок try, чтобы что-то сделать, и перехватывать ошибки как исключения внутри блока except.
[python_ad_block]
Итак, теперь давайте используем полученные знания для обработки исключений в Python. Приступим!
Обработка ZeroDivisionError
Рассмотрим функцию divide(), показанную ниже. Она принимает два аргумента – num и div – и возвращает частное от операции деления num/div.
def divide(num,div):
return num/div
Вызов функции с разными аргументами возвращает ожидаемый результат:
res = divide(100,8) print(res) # Output # 12.5 res = divide(568,64) print(res) # Output # 8.875
Этот код работает нормально, пока вы не попробуете разделить число на ноль:
divide(27,0)
Вы видите, что программа выдает ошибку ZeroDivisionError:
# Output
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-19-932ea024ce43> in <module>()
----> 1 divide(27,0)
<ipython-input-1-c98670fd7a12> in divide(num, div)
1 def divide(num,div):
----> 2 return num/div
ZeroDivisionError: division by zero
Можно обработать деление на ноль как исключение, выполнив следующие действия:
- В блоке
tryпоместите вызов функцииdivide(). По сути, вы пытаетесь разделитьnumнаdiv(try в переводе с английского — «пытаться», — прим. перев.). - В блоке
exceptобработайте случай, когдаdivравен 0, как исключение. - В результате этих действий при делении на ноль больше не будет выбрасываться ZeroDivisionError. Вместо этого будет выводиться сообщение, информирующее пользователя, что он попытался делить на ноль.
Вот как все это выглядит в коде:
try:
res = divide(num,div)
print(res)
except ZeroDivisionError:
print("You tried to divide by zero :( ")
При корректных входных данных наш код по-прежнему работает великолепно:
divide(10,2) # Output # 5.0
Когда же пользователь попытается разделить на ноль, он получит уведомление о возникшем исключении. Таким образом, программа завершается корректно и без ошибок.
divide(10,0) # Output # You tried to divide by zero :(
Обработка TypeError
В этом разделе мы разберем, как использовать try и except для обработки TypeError в Python.
Рассмотрим функцию add_10(). Она принимает число в качестве аргумента, прибавляет к нему 10 и возвращает результат этого сложения.
def add_10(num):
return num + 10
Вы можете вызвать функцию add_10() с любым числом, и она будет работать нормально, как показано ниже:
result = add_10(89) print(result) # Output # 99
Теперь попробуйте вызвать функцию add_10(), передав ей в качестве аргумента не число, а строку.
add_10 ("five")
Ваша программа вылетит со следующим сообщением об ошибке:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-15-9844e949c84e> in <module>()
----> 1 add_10("five")
<ipython-input-13-2e506d74d919> in add_10(num)
1 def add_10(num):
----> 2 return num + 10
TypeError: can only concatenate str (not "int") to str
Сообщение об ошибке TypeError: can only concatenate str (not "int") to str говорит о том, что можно сложить только две строки, а не добавить целое число к строке.
Обработаем TypeError:
- В блок try мы помещаем вызов функции
add_10()с my_num в качестве аргумента. Если аргумент допустимого типа, исключений не возникнет. - В противном случае срабатывает блок
except, в который мы помещаем вывод уведомления для пользователя о том, что аргумент имеет недопустимый тип.
Это показано ниже:
my_num = "five"
try:
result = add_10(my_num)
print(result)
except TypeError:
print("The argument `num` should be a number")
Поскольку теперь вы обработали TypeError как исключение, при передаче невалидного аргумента ошибка не возникает. Вместо нее выводится сообщение, что аргумент имеет недопустимый тип.
The argument `num` should be a number
Обработка IndexError
Если вам приходилось работать со списками или любыми другими итерируемыми объектами, вы, вероятно, сталкивались с IndexError.
Это связано с тем, что часто бывает сложно отслеживать все изменения в итерациях. И вы можете попытаться получить доступ к элементу по невалидному индексу.
В этом примере список my_list состоит из 4 элементов. Допустимые индексы — 0, 1, 2 и 3 и -1, -2, -3, -4, если вы используете отрицательную индексацию.
Поскольку 2 является допустимым индексом, вы видите, что элемент с этим индексом (C++) распечатывается:
my_list = ["Python","C","C++","JavaScript"] print(my_list[2]) # Output # C++
Но если вы попытаетесь получить доступ к элементу по индексу, выходящему за пределы допустимого диапазона, вы столкнетесь с IndexError:
print(my_list[4])
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-7-437bc6501dea> in <module>()
1 my_list = ["Python","C","C++","JavaScript"]
----> 2 print(my_list[4])
IndexError: list index out of range
Теперь вы уже знакомы с шаблоном, и вам не составит труда использовать try и except для обработки данной ошибки.
В приведенном ниже фрагменте кода мы пытаемся получить доступ к элементу по индексу search_idx.
search_idx = 3
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
Здесь search_idx = 3 является допустимым индексом, поэтому в результате выводится соответствующий элемент — JavaScript.
Если search_idx находится за пределами допустимого диапазона индексов, блок except перехватывает IndexError как исключение, и больше нет длинных сообщений об ошибках.
search_idx = 4
try:
print(my_list[search_idx])
except IndexError:
print("Sorry, the list index is out of range")
Вместо этого отображается сообщение о том, что search_idx находится вне допустимого диапазона индексов:
Sorry, the list index is out of range
Обработка KeyError
Вероятно, вы уже сталкивались с KeyError при работе со словарями в Python.
Рассмотрим следующий пример, где у нас есть словарь my_dict.
my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
search_key = "non-existent key"
print(my_dict[search_key])
В словаре my_dict есть 3 пары «ключ-значение»: key1:value1, key2:value2 и key3:value3.
Теперь попытаемся получить доступ к значению, соответствующему несуществующему ключу non-existent key.
Как и ожидалось, мы получим KeyError:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-2-2a61d404be04> in <module>()
1 my_dict ={"key1":"value1","key2":"value2","key3":"value3"}
2 search_key = "non-existent key"
----> 3 my_dict[search_key]
KeyError: 'non-existent key'
Вы можете обработать KeyError почти так же, как и IndexError.
- Пробуем получить доступ к значению, которое соответствует ключу, определенному
search_key. - Если
search_key— валидный ключ, мы распечатываем соответствующее значение. - Если ключ невалиден и возникает исключение — задействуется блок except, чтобы сообщить об этом пользователю.
Все это можно видеть в следующем коде:
try:
print(my_dict[search_key])
except KeyError:
print("Sorry, that's not a valid key!")
# Output:
# Sorry, that's not a valid key!
Если вы хотите предоставить дополнительный контекст, например имя невалидного ключа, это тоже можно сделать. Возможно, ключ оказался невалидным из-за ошибки в написании. Если вы укажете этот ключ в сообщении, это поможет пользователю исправить опечатку.
Вы можете сделать это, перехватив невалидный ключ как <error_msg> и используя его в сообщении, которое печатается при возникновении исключения:
try:
print(my_dict[search_key])
except KeyError as error_msg:
print(f"Sorry,{error_msg} is not a valid key!")
Обратите внимание, что теперь в сообщении об ошибки указано также и имя несуществующего ключа:
Sorry, 'non-existent key' is not a valid key!
Обработка FileNotFoundError
При работе с файлами в Python часто возникает ошибка FileNotFoundError.
В следующем примере мы попытаемся открыть файл my_file.txt, указав его путь в функции open(). Мы хотим прочитать файл и вывести его содержимое.
Однако мы еще не создали этот файл в указанном месте.
my_file = open("/content/sample_data/my_file.txt")
contents = my_file.read()
print(contents)
Поэтому, попытавшись запустить приведенный выше фрагмент кода, мы получим FileNotFoundError:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-4-4873cac1b11a> in <module>()
----> 1 my_file = open("my_file.txt")
FileNotFoundError: [Errno 2] No such file or directory: 'my_file.txt'
А с помощью try и except мы можем сделать следующее:
- Попробуем открыть файл в блоке
try. - Обработаем
FileNotFoundErrorв блокеexcept, сообщив пользователю, что он попытался открыть несуществующий файл. - Если блок
tryзавершается успешно и файл действительно существует, прочтем и распечатаем содержимое. - В блоке
finallyзакроем файл, чтобы не терять ресурсы. Файл будет закрыт независимо от того, что происходило на этапах открытия и чтения.
try:
my_file = open("/content/sample_data/my_file.txt")
except FileNotFoundError:
print(f"Sorry, the file does not exist")
else:
contents = my_file.read()
print(contents)
finally:
my_file.close()
Обратите внимание: мы обработали ошибку как исключение, и программа завершает работу, отображая следующее сообщение:
Sorry, the file does not exist
Теперь рассмотрим случай, когда срабатывает блок else. Файл my_file.txt теперь присутствует по указанному ранее пути.

Вот содержимое этого файла:

Теперь повторный запуск нашего кода работает должным образом.
На этот раз файл my_file.txt присутствует, поэтому запускается блок else и содержимое распечатывается, как показано ниже:

Надеемся, теперь вы поняли, как обрабатывать исключения при работе с файлами.
Заключение
В этом руководстве мы рассмотрели, как обрабатывать исключения в Python с помощью try и except.
Также мы разобрали на примерах, какие типы исключений могут возникать и как при помощи except ловить наиболее распространенные ошибки.
Надеемся, вам понравился этот урок. Успехов в написании кода!
Перевод статьи «Python Try and Except Statements – How to Handle Exceptions in Python».
На чтение 13 мин Просмотров 4к. Опубликовано 12.07.2021
Содержание
- Введение в тему
- Что такое исключения
- Перехват исключений
- Несколько блоков except
- Вложенные блоки и else
- Finally
- Управление исключениями
- Пользовательские исключения
- Запись в лог
- Иерархия исключений
Введение в тему
Зачастую возникают ситуации, когда программа или скрипт работают не так, как задумывал программист. Чаще всего это бывает из-за ввода неожиданных данных. Для обработки таких ситуаций в языке программирования Python есть конструкция try except else finally. Это называется обработкой исключений и позволяет контролировать аварийные случаи. Об этом мощном инструменте мы и поговорим в данном уроке.
Что такое исключения
Работа программиста во многом связана с возникающими в коде ошибками. Их приходится находить и исправлять. Особенно опасны так называемые гейзенбаги – ошибки, которые сложно воспроизвести. Так же существуют скрытые ошибки, их ещё можно назвать логическими. Ещё есть ошибки, которые и вовсе не зависят от программы. Представьте, у Вас есть программа-скрапер, которая автоматически скачивает картинки из соцсети. Заходит она на очередную страницу… А сервер сети поломался. Программа выдаст ошибку.
Если говорить именно о Питоне, то сложность ещё и в том, что это не компилируемый, а интерпретируемый язык, то есть код выполняется «на лету», строка за строкой. Это означает, что у Пайтон-программиста нет возможности отловить ошибки на этапе компиляции. Ещё одна сложность заключается в том, что Python – язык со строгой, но динамической типизацией. Частично это решается в последних версиях языка средством под названием «аннотирование типов», но полностью проблемы не устраняет.
И так, существуют следующие виды ошибок:
- Синтаксические – когда программист нарушает правила самого языка, к примеру, допускает опечатку в ключевом слове;
- Логические – когда в коде используется не верная логика;
- Ввода – когда программист предполагал от пользователя ввода одних данных, а введены другие. К примеру, создатель сайта задумывал, что число в форме будет указано с использованием точки в качестве разделителя, а пользователь ввёл «3,14». Именно этот вид ошибок – излюбленная лазейка хакеров.
Синтаксические ошибки – самые простые, поскольку интерпретатор сам сообщит Вам о них при попытке запустить скрипт.
Простой пример, напечатали команду print с большой буквы:
Print('Hello World!')
# Вывод
Traceback (most recent call last):
File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 1, in <module>
Print('Hello World!')
NameError: name 'Print' is not defined
Process finished with exit code 1
Логические ошибки – самые сложные в обработке. Сложность в том, что скрипт запускается и не выдаёт никаких исключений, но результат работы отличается от ожидаемого. В чём причина и где её искать? Понятно, что использован не правильный алгоритм. В таких ситуациях можно посоветовать разбить алгоритм на части и проверять значение переменных в контрольных точках. Вот пример такой ошибки:
from random import randint
random_list = 5
sorted_list = []
for i in range(random_list):
sorted_list.append(randint(1, 99))
print(sorted_list)
for i in range(random_list - 1):
for j in range(random_list - i - 1):
if sorted_list[j] > sorted_list[j + 1]:
sorted_list[j] = sorted_list[j + 1]
print(sorted_list)
# Вывод:
[95, 57, 16, 29, 82]
[16, 16, 16, 29, 82]
В этом примере программист хотел сделать сортировку пузырьком, но допустил ошибку. А Вы сможете её найти?
Ошибки ввода, как уже говорилось, это ошибки, чаще всего возникающие из-за того, что программист и пользователь не поняли друг друга. Вот код примера, приведённого выше:
x_var = input('Введите число и мы его разделим на 10 n')
print('Результат деления:', float(x_var) / 10)
# Вывод:
Введите число и мы его разделим на 10
3,14
Traceback (most recent call last):
File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 2, in <module>
print('Результат деления:', float(x_var) / 10)
ValueError: could not convert string to float: '3,14'
Как вы видите, интерпретатор «выбрасывает» исключение «ValueError» — ошибка значения и останавливает выполнение кода.
Перехват исключений
Если Вам не подходит стандартное поведение языка при возникновении исключений – остановка выполнения, Вы можете перехватить исключение и обработать его. Для таких ситуаций и существует конструкция try except. Данный механизм Python позволяет контролировать непредвиденные ситуации и действовать исходя из новых условий. Проиллюстрируем это используя предыдущий пример:
x_var = input('Введите число и мы его разделим на 10 n') try: print('Результат деления:', float(x_var) / 10) except ValueError: print('Вы ввели число с запятой, а надо с точкой') print('Программа завершена') # Вывод: Введите число и мы его разделим на 10 3,14 Вы ввели число с запятой, а надо с точкой Программа завершена
Как Вы можете заметить, программа выполнена полностью. Об этом свидетельствует последняя строка вывода. В блок try необходимо заключить тот участок кода, в котором может возникнуть исключение, а в блоке except – его обработку. Обратите внимание, что в блоке except можно не указывать вид ошибки и тогда будет обработано любое возникшее в блоке try исключение.
Несколько блоков except
Можно использовать несколько блоков except и обрабатывать в каждом блоке отдельный вид ошибки. Немного перепишем программу из предыдущего примера:
x_var = input('Введите число и мы разделим на него 10 n')
try:
print('Результат деления:', 10 / float(x_var))
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
print('Программа завершена')
# Вывод:
Введите число и мы разделим на него 10
0
Вы ввели ноль, но на него делить нельзя
Программа завершена
Хорошей практикой является написание сперва блоков для конкретных ошибок, а затем для общих случаев, поскольку всех ситуаций не предусмотреть:
x_var = input('Введите число и мы разделим на него 10 n')
try:
Print('Результат деления:', 10 / float(x_var))
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
except:
print('Не знаю что, но что-то точно пошло не так')
print('Программа завершена')
# Вывод:
Введите число и мы разделим на него 10
10
Не знаю что, но что-то точно пошло не так
Программа завершена
Вложенные блоки и else
Блоки try-except можно вкладывать друг в друга, если в этом есть необходимость.
Здесь же мы используем блок else. Этот блок должен содержать код, который выполнится если не возникнет исключений.
x_var = input('Введите число и мы разделим на него 10 n')
try:
result = 10 / float(x_var)
try:
print('Результат деления:', result)
except:
print('Не знаю что, но что-то точно пошло не так')
else:
print('Полёт нормальный')
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
else:
print('Программа выполнена без ошибок')
print('Программа завершена')
# Вывод:
Введите число и мы разделим на него 10
10
Результат деления: 1.0
Полёт нормальный
Программа выполнена без ошибок
Программа завершена
Кстати, здесь допущена логическая ошибка. Найдёте?
Finally
Встречаются ситуации, когда необходимо выполнить какую-то часть кода в независимости от того, было исключение или нет. Для этого существует блок finally:
try:
result = 10 / float(x_var)
try:
Print('Результат деления:', result)
except:
print('Не знаю что, но что-то точно пошло не так')
else:
print('Полёт нормальный')
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
finally:
print('Программа завершена')
# Вывод:
Введите число и мы разделим на него 10
10
Не знаю что, но что-то точно пошло не так
Программа завершена
Управление исключениями
В Пайтоне есть возможность создавать свои виды исключений. Ниже мы рассмотрим как это делать, а ещё такую важную вещь как логгирование.
Пользовательские исключения
В Python есть ключевое слово raise. Нужно оно для того чтоб самостоятельно вызывать исключения:
raise Exception("Моя ошибка")
# Вывод:
Traceback (most recent call last):
File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 1, in <module>
raise Exception("Моя ошибка")
Exception: Моя ошибка
Такие ошибки тоже можно ловить в try и обрабатывать в except:
x_var = float(input('Введите числоn'))
try:
if x_var > 10:
raise Exception()
except:
print('Что-то пошло не так. Возможно, число слишком большое')
# Вывод:
Введите число
11
Что-то пошло не так. Возможно, число слишком большое
Для того чтобы создать свой тип исключения, необходимо объявить новый класс и унаследовать его от базового типа Exception. Текст ошибки можно передавать используя дандер метод __str__:
class MyException(Exception):
def __str__(self):
return 'Число слишком большое'
x_var = float(input('Введите числоn'))
try:
if x_var > 10:
raise MyException()
except MyException:
print(MyException())
# Вывод:
Введите число
11
Число слишком большое
Так же, текст ошибки можно передавать переопределяя родительский атрибут message:
class MyException(Exception):
def __init__(self):
self.message = 'Число слишком большое'
super().__init__(self.message)
x_var = float(input('Введите числоn'))
try:
if x_var > 10:
raise MyException()
except MyException:
print(MyException())
# Вывод:
Введите число
11
Число слишком большое
Раз мы объявили метод __init__, следует сказать, что в него можно передавать аргументы:
class MyException(Exception):
def __init__(self, x):
self.x = x
self.message = 'Число {} слишком большое'.format(self.x)
super().__init__(self.message)
x_var = float(input('Введите числоn'))
if x_var > 10:
raise MyException(x_var)
# Вывод:
Введите число
11
Traceback (most recent call last):
File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 9, in <module>
raise MyException(x_var)
__main__.MyException: Число 11.0 слишком большое
Запись в лог
Часто для отладки программ используют логгирование. Это вывод, чаще всего в отдельный файл, каких-то сообщений, содержащих информацию о том, как программа работает. В том числе, писать в лог можно и текст исключений. В Питоне для этого создали специальный модуль и даже включили его в стандартную библиотеку. Сперва его надо импортировать в Ваш код, а затем указать тип лога:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug(" Сообщения про отладку")
logging.info(" Информационные сообщения")
logging.warning(" Предупреждения")
logging.error(" Сообщения с ошибками")
logging.critical(" Ну очень важные сообщения")
# Вывод:
DEBUG:root: Сообщения про отладку
INFO:root: Информационные сообщения
WARNING:root: Предупреждения
ERROR:root: Сообщения с ошибками
CRITICAL:root: Ну очень важные сообщения
Параметр level= указывает, сообщения какого уровня заносить в лог. К примеру, если указать ‘level= logging.ERROR’, то логгироваться будут только сообщения уровня error и critical. Объединим логгирование и обработку исключений:
import logging
logging.basicConfig(filename="log.txt", level=logging.WARNING)
try:
print(10 / 0)
except Exception:
logging.error(str(Exception))
Содержимое файла log.txt:
ERROR:root:<class 'Exception'>
Иерархия исключений
В Python есть иерархия исключений. Это происходит из-за того, что их классы наследуются друг от друга. Вот полный список:
BaseException — базовое исключение, от которого берут начало все остальные
+SystemExit — исключение, порождаемое функцией sys.exit при выходе из программы
+KeyboardInterrupt — порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C)
+GeneratorExit — порождается при вызове метода close объекта generator
+Exception – исключения
++StopIteration — порождается встроенной функцией next, если в итераторе больше нет элементов
++StopAsyncIteration — используется для остановки асинхронного прохода
++ArithmeticError — арифметическая ошибка
+++FloatingPointError
+++OverflowError
+++ZeroDivisionError
++AssertionError— выражение в функции assert ложно
++AttributeError — объект не имеет данного атрибута (значения или метода)
++BufferError— операция, связанная с буфером, не может быть выполнена
++EOFError— функция наткнулась на конец файла и не смогла прочитать то, что хотела
++ImportError — не удалось импортирование модуля или его атрибута
+++ModuleNotFoundError
++LookupError— некорректный индекс или ключ
+++IndexError
+++KeyError
++MemoryError— недостаточно памяти
++NameError — не найдено переменной с таким именем
+++UnboundLocalError
++OSError — ошибка, связанная с системой
+++BlockingIOError
+++ChildProcessError
+++ConnectionError
++++BrokenPipeError
++++ConnectionAbortedError
++++ConnectionRefusedError
++++ConnectionResetError
+++FileExistsError
+++FileNotFoundError
+++InterruptedError
+++IsADirectoryError
+++NotADirectoryError
+++PermissionError
+++ProcessLookupError
+++TimeoutError
++ReferenceError — попытка доступа к атрибуту со слабой ссылкой
++RuntimeError — возникает, когда исключение не попадает ни под одну из других категорий
+++NotImplementedError
+++RecursionError
++SyntaxError — синтаксическая ошибка
++IndentationError
++TabError
++SystemError — внутренняя ошибка
++TypeError — операция применена к объекту несоответствующего типа
++ValueError — функция получает аргумент правильного типа, но некорректного значения
+++UnicodeError
++++UnicodeDecodeError
++++UnicodeEncodeError
++++UnicodeTranslateError
++Warning — предупреждение
+++DeprecationWarning
+++PendingDeprecationWarning
+++RuntimeWarning
+++SyntaxWarning
+++UserWarning
+++FutureWarning
+++ImportWarning
+++UnicodeWarning
+++BytesWarning
+++ResourceWarning