Python try except вывести текст ошибки

Exceptions: обработка ошибок с помощью try except else finally raise в Python
Содержание

Введение
Пример с базовым 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)
return1

>>> 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()

SyntaxError

SyntaxError поднимается когда допущена ошибка в синтаксисе языка, например, использован
несуществующий оператор.

Python 3.8.10 (default, Nov 14 2022, 12:59:47)
[GCC 9.4.0] on linux
Type «help», «copyright», «credits» or «license» for more information.
>>>
>>>
>>> 0 <> 0
File «<stdin>», line 1
0 <> 0
^
SyntaxError: invalid syntax

Пример из статьи

__future__

Похожие статьи

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 в Python

В нашем примере Traceback содержится следующую информацию (читаем снизу вверх):

  1. TypeError — тип ошибки (означает, что операция не может быть выполнена с переменной этого типа);
  2. can only concatenate str (not "int") to str — подробное описание ошибки (конкатенировать можно только строку со строкой);
  3. Стек вызова функций (1-я линия — место, 2-я линия — код). В нашем примере видно, что в файле «test.py» на 11-й линии был вызов функции «a» со строковым аргументом «10». Далее был вызов функции «b». print(value + 1) это последнее, что было выполнено — тут и произошла ошибка.
  4. 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

В программе может возникнуть несколько исключений, например:

  1. Ошибка преобразования введенных значений к типу float («ValueError»);
  2. Деление на ноль («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 можно ознакомиться в официальной документации.

Обработка исключений в 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 предусмотрены специальные синтаксические конструкции. Кроме того, в нем есть большая библиотека готовых исключений, а также возможность создавать собственные.

Применение 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!’)]. После чего исключение остановит текущее выполнение и перейдет дальше по стеку вызовов до тех пор, пока исключение не будет обработано.

Исключения также используются для управления ошибками, которые возникают в циклах, при работе с базой данных, доступе к сети и т.д.

Обработка исключений — это искусство, которое помогает в написании надежного и качественного кода.

Советы по использованию Try Except Python 3, Try-Except-Else и многое другое

Как в 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 с помощью 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

Можно обработать деление на ноль как исключение, выполнив следующие действия:

  1. В блоке try поместите вызов функции divide(). По сути, вы пытаетесь разделить num на div (try в переводе с английского — «пытаться», — прим. перев.).
  2. В блоке except обработайте случай, когда div равен 0, как исключение.
  3. В результате этих действий при делении на ноль больше не будет выбрасываться 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».

При выполнении заданий к главам вы скорее всего нередко сталкивались с возникновением различных ошибок. На этой главе мы изучим подход, который позволяет обрабатывать ошибки после их возникновения.

Напишем программу, которая будет считать обратные значения для целых чисел из заданного диапазона и выводить их в одну строку с разделителем «;». Один из вариантов кода для решения этой задачи выглядит так:

print(";".join(str(1 / x) for x in range(int(input()), int(input()) + 1)))

Программа получилась в одну строчку за счёт использования списочных выражений. Однако при вводе диапазона чисел, включающем в себя 0 (например, от -1 до 1), программа выдаст следующую ошибку:

ZeroDivisionError: division by zero

В программе произошла ошибка «деление на ноль». Такая ошибка, возникающая при выполнении программы и останавливающая её работу, называется исключением.

Попробуем в нашей программе избавиться от возникновения исключения деления на ноль. Пусть при попадании 0 в диапазон чисел, обработка не производится и выводится сообщение «Диапазон чисел содержит 0». Для этого нужно проверить до списочного выражения наличие нуля в диапазоне:

interval = range(int(input()), int(input()) + 1)
if 0 in interval:
    print("Диапазон чисел содержит 0.")
else:
    print(";".join(str(1 / x) for x in interval))

Теперь для диапазона, включающего в себя 0, например, от -2 до 2, исключения ZeroDivisionError не возникнет. Однако при вводе строки, которую невозможно преобразовать в целое число (например, «a»), будет вызвано другое исключение:

ValueError: invalid literal for int() with base 10: 'a'

Произошло исключение ValueError. Для борьбы с этой ошибкой нам придётся проверить, что строка состоит только из цифр. Сделать это нужно до преобразования в число. Тогда наша программа будет выглядеть так:

start = input()
end = input()
# Метод lstrip("-"), удаляющий символы "-" в начале строки, нужен для учёта
# отрицательных чисел, иначе isdigit() вернёт для них False
if not (start.lstrip("-").isdigit() and end.lstrip("-").isdigit()):
    print("Необходимо ввести два числа.")
else:
    interval = range(int(start), int(end) + 1)
    if 0 in interval:
        print("Диапазон чисел содержит 0.")
    else:
        print(";".join(str(1 / x) for x in interval))

Теперь наша программа работает без ошибок и при вводе строк, которые нельзя преобразовать в целое число.

Подход, который был нами применён для предотвращения ошибок, называется «Look Before You Leap» (LBYL), или «посмотри перед прыжком». В программе, реализующей такой подход, проверяются возможные условия возникновения ошибок до исполнения основного кода.

Подход LBYL имеет недостатки. Программу из примера стало сложнее читать из-за вложенного условного оператора. Проверка условия, что строка может быть преобразована в число, выглядит даже сложнее, чем списочное выражение. Вложенный условный оператор не решает поставленную задачу, а только лишь проверяет входные данные на корректность. Легко заметить, что решение основной задачи заняло меньше времени, чем составление условий проверки корректности входных данных.

Существует другой подход для работы с ошибками: «Easier to Ask Forgiveness than Permission» (EAFP) или «проще извиниться, чем спрашивать разрешение». В этом подходе сначала исполняется код, а в случае возникновения ошибок происходит их обработка. Подход EAFP реализован в Python в виде обработки исключений.

Исключения в Python являются классами ошибок. В Python есть много стандартных исключений. Они имеют определённую иерархию за счёт механизма наследования классов. В документации Python версии 3.10.8 приводится следующее дерево иерархии стандартных исключений:

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

Для обработки исключения в Python используется следующий синтаксис:

try:
    <код , который может вызвать исключения при выполнении>
except <классисключения_1>:
    <код обработки исключения>
except <классисключения_2>:
    <код обработки исключения>
...
else:
    <код выполняется, если не вызвано исключение в блоке try>
finally:
    <код , который выполняется всегда>

Блок try содержит код, в котором нужно обработать исключения, если они возникнут. При возникновении исключения интерпретатор последовательно проверяет в каком из блоков except обрабатывается это исключение. Исключение обрабатывается в первом блоке except, обрабатывающем класс этого исключения или базовый класс возникшего исключения. Необходимо учитывать иерархию исключений для определения порядка их обработки в блоках except. Начинать обработку исключений следует с более узких классов исключений. Если начать с более широкого класса исключения, например, Exception, то всегда при возникновении исключения будет срабатывать первый блок except. Сравните два следующих примера. В первом порядок обработки исключений указан от производных классов к базовым, а во втором – наоборот.

try:
    print(1 / int(input()))
except ZeroDivisionError:
    print("Ошибка деления на ноль.")
except ValueError:
    print("Невозможно преобразовать строку в число.")
except Exception:
    print("Неизвестная ошибка.")

При вводе значений «0» и «a» получим ожидаемый соответствующий возникающим исключениям вывод:

Невозможно преобразовать строку в число.

и

Ошибка деления на ноль.

Второй пример:

try:
    print(1 / int(input()))
except Exception:
    print("Неизвестная ошибка.")
except ZeroDivisionError:
    print("Ошибка деления на ноль.")
except ValueError:
    print("Невозможно преобразовать строку в число.")

При вводе значений «0» и «a» получим в обоих случаях неинформативный вывод:

Неизвестная ошибка.

Необязательный блок else выполняет код в случае, если в блоке try не вызвано исключение. Добавим блок else в пример для вывода сообщения об успешном выполнении операции:

try:
    print(1 / int(input()))
except ZeroDivisionError:
    print("Ошибка деления на ноль.")
except ValueError:
    print("Невозможно преобразовать строку в число.")
except Exception:
    print("Неизвестная ошибка.")
else:
    print("Операция выполнена успешно.")

Теперь при вводе корректного значения, например, «5», вывод программы будет следующим:

2.0
Операция выполнена успешно.

Блок finally выполняется всегда, даже если возникло какое-то исключение, не учтённое в блоках except или код в этих блоках сам вызвал какое-либо исключение. Добавим в нашу программу вывод строки «Программа завершена» в конце программы даже при возникновении исключений:

try:
    print(1 / int(input()))
except ZeroDivisionError:
    print("Ошибка деления на ноль.")
except ValueError:
    print("Невозможно преобразовать строку в число.")
except Exception:
    print("Неизвестная ошибка.")
else:
    print("Операция выполнена успешно.")
finally:
    print("Программа завершена.")

Перепишем код, созданный с применением подхода LBYL, для первого примера из этой главы с использованием обработки исключений:

try:
    print(";".join(str(1 / x) for x in range(int(input()), int(input()) + 1)))
except ZeroDivisionError:
    print("Диапазон чисел содержит 0.")
except ValueError:
    print("Необходимо ввести два числа.")

Теперь наша программа читается намного легче. При этом создание кода для обработки исключений не заняло много времени и не потребовало проверки сложных условий.

Исключения можно принудительно вызывать с помощью оператора raise. Этот оператор имеет следующий синтаксис:

raise <класс исключения>(параметры)

В качестве параметра можно, например, передать строку с сообщением об ошибке.

В Python можно создавать свои собственные исключения. Синтаксис создания исключения такой же, как и у создания класса. При создании исключения его необходимо наследовать от какого-либо стандартного класса-исключения.

Напишем программу, которая выводит сумму списка целых чисел, и вызывает исключение, если в списке чисел есть хотя бы одно чётное или отрицательное число. Создадим свои классы исключений:

  • NumbersError – базовый класс исключения;
  • EvenError – исключение, которое вызывается при наличии хотя бы одного чётного числа;
  • NegativeError – исключение, которое вызывается при наличии хотя бы одного отрицательного числа.
class NumbersError(Exception):
    pass


class EvenError(NumbersError):
    pass


class NegativeError(NumbersError):
    pass


def no_even(numbers):
    if all(x % 2 != 0 for x in numbers):
        return True
    raise EvenError("В списке не должно быть чётных чисел")


def no_negative(numbers):
    if all(x >= 0 for x in numbers):
        return True
    raise NegativeError("В списке не должно быть отрицательных чисел")


def main():
    print("Введите числа в одну строку через пробел:")
    try:
        numbers = [int(x) for x in input().split()]
        if no_negative(numbers) and no_even(numbers):
            print(f"Сумма чисел равна: {sum(numbers)}.")
    except NumbersError as e:  # обращение к исключению как к объекту
        print(f"Произошла ошибка: {e}.")
    except Exception as e:
        print(f"Произошла непредвиденная ошибка: {e}.")

        
if __name__ == "__main__":
    main()

Обратите внимание: в программе основной код выделен в функцию main. А код вне функций содержит только условный оператор и вызов функции main при выполнении условия __name__ == "__main__". Это условие проверяет, запущен ли файл как самостоятельная программа или импортирован как модуль.

Любая программа, написанная на языке программирования Python может быть импортирована как модуль в другую программу. В идеологии Python импортировать модуль – значит полностью его выполнить. Если основной код модуля содержит вызовы функций, ввод или вывод данных без использования указанного условия __name__ == "__main__", то произойдёт полноценный запуск программы. А это не всегда удобно, если из модуля нужна только отдельная функция или какой-либо класс.

При изучении модуля itertools, мы говорили о том, как импортировать модуль в программу. Покажем ещё раз два способа импорта на примере собственного модуля.

Для импорта модуля из файла, например example_module.py, нужно указать его имя, если он находится в той же папке, что и импортирующая его программа:

import example_module

Если требуется отдельный компонент модуля, например функция или класс, то импорт можно осуществить так:

from example_module import some_function, ExampleClass

Обратите внимание: при втором способе импортированные объекты попадают в пространство имён новой программы. Это означает, что они будут объектами новой программы, и в программе не должно быть других объектов с такими же именами.

Ошибок не допускает только тот, кто ничего не делает и программирование не исключение. С ростом кода и объема разработки, также растет вероятность получить error в терминале. Именно по причине весовой вероятности появления ошибок исключения в python и других языках программирования — это обязательная часть.

Значения исключений и ошибок в Python

Как упоминалась выше, от ошибок в коде никто не застрахован и если новички часто совершают банальные опечатки, то у профессионалов найти ошибку крайне сложно. Когда приходиться часами, а то и днями перебирать все базовые и наследуемые классы очень жалеешь, что прописал обработчик.

В Python обработка исключений имеет колоссальное значение. Неполадки возможны как элементарные, так и скрытые в особенностях языка или логике построения. Если программист считает, что пользователь никогда не сделает ошибки – он их обязательно совершит. Идеального решения в программном коде не существует и существовать не может, следовательно, добавлять исключение и уметь их обрабатывать профессиональная необходимость.

Как устроен механизм исключений

Обычно код выполняться построчно в случае, когда дальнейшее выполнение становится невозможным, программа возвращает exceptions. В отсутствие обработчика исключений ошибка не выявляется и на этом работа программы заканчивается.

На курсах python https://volgograd.videoforme.ru/computer-programming-school/python-for-beginners объясняют, что обработка ошибок происходит во многом за счет пойманного exceptions. Код, который потенциально может быть проломным, оборачивается в своего рода ловушку. Если проблем нет, то все проходит стандартно, но только появляться exceptions мы выходим из потенциально проблемного участка и идем по пути исключения. По сути данный механизм можно условно сравнить if – else, когда все хорошо мы в if, когда сломалось в else (при этом в else также прилетит exceptions).

Синтаксические ошибки (SyntaxError)

От ошибок в синтаксисе никто не застрахован. Конечно, значительно чаще этим грешат новички программирования. Возьмем пример:

.py

employee = [

['Иванов', 'бухгалтер'],

['Денисов', 'инженер'],

]

for employee_name, employee_post in employee:

label = 'Имя: { employee_name }. Должность: { employee_post }'.format(

employeу_name = employeу_name

employee_post = employee_post

)

print(label) # SyntaxError

Код кажется простым и понятным, но в нем скрыта едва заметная ошибка, которая не даст коду запуститься. Пример показывает, что простая запятая легко сломает программу. Естественно, в интерпретированной среде python выдает ошибку, особенно настолько элементарную. Ошибка SyntaxError иногда преследует программиста, когда меняют функции внутри библиотеки, или он просто утомился. В остальном это беда новичков, которые только знакомятся с языком и его синтаксисом.

Недостаточно памяти (OutofMemoryError)

Ошибки python вроде нехватки памяти далеко не редки, причин на то очень много. Разберём три основные:

Сам язык Питон очень ресурсоемкий язык, он однопоточный и при неграмотном подходе способен быстро забрать всю выделенную память устройства.

Утечка данных – переменные в Питон ссылочного типа и в теории он их удаляет, как только они ему не нужны. Но вполне можно организовать ситуацию, когда данные не будут удаляться и постепенно забьют все свободную память.

Бесконечные циклы – когда условия выхода из цикла никогда не наступят, в какой-то момент выделяемая память просто закончиться.

Ошибка рекурсии (RecursionError)

Рекурсия сам по себе не самый безопасный подход, но благодаря ей можно значительно облегчить код. Типы ошибок python вроде RecursionError, по сути, это срабатывание защиты внутри самого языка. Программисту выходят предупреждения, что, вероятно, запустил бесконечную рекурсию и выделенные под предел достигнут.

Простой пример бесконечной рекурсии:

def recurs():

recurs()

recurs() # RecursionError

Ошибка отступа (IndentationError)

Виды ошибок в Питоне вроде неправильных отступов, опять же можно отнести к ошибкам новичков. В Python теле любого логического процесса обозначается четырьмя пробелами. Если есть «:», а внизу на том же уровне идет код — это явная ошибка.

Пример такой явной ошибки:

def spaceBar():

pass

spaceBar() # IndentationError

Типы исключений

Исключения позволяют застраховаться программисту от вероятных неисправностей. Более того, становиться возможным отладить и исправить программу на разных этапах разработки. Обработка исключений в Питон можно назвать фундаментальным навыком, необходимым для развития python разработчика.

Исключение берет свою основу от BaseException, базового исключения от которого наследуются все остальные, именно этот базовый класс позволяет создавать собственные исключения.

Наследуясь от базового класса, исключения делятся на:

  • SystemExit
  • KeyboardInterrupt
  • GeneratorExit
  • Exception

Exception единственное несистемное исключение, с которым работает программист. От этого класса идут следующие виды исключений.

Ошибка типа (TypeError)

Один из довольно распространённых типов ошибок проследить все цепочку наследования легко: BaseException, Exception, TypeError. Данное исключение сработает, когда указанный тип данных не существует.

Ошибка деления на ноль (ZeroDivisionError)

Очень часто встречающаяся ошибка при различных делениях. Питон динамичен, но строго типизирован. Так в простой математике делить на ноль нельзя, но ситуация с таким делением может возникнуть по очень многим причинам. Python 3 исключения такого типа сработает к таком элементарном коде:

print( 0 / 0 ) # ZeroDivisionError

Встроенные исключения

Встроенные исключения – это виды ошибок в Питоне, условия исполнения которых четко прописаны в языке. Здесь можно вспомнить деление на ноль, отсутствие или лишние пробелы.

Ошибка прерывания с клавиатуры (KeyboardInterrupt)

Системное исключение KeyboardInterrupt дает прерывание программы какой-то клавишей или сочетанием клавиш, по умолчанию используется Ctrl+C. Это удобный способ прервать, к примеру, бесконечный цикл, когда явно программа работает неправильно.

Как обрабатывать исключения в Python (try except)

Стандартно в Python 3-я обработка исключений строится на try – except, эта конструкция очень часто встречающийся в разных языках программирования. Код обработки исключения выглядит так:

try: # место кода, где возможно срабатывание исключения

a= 10 / 0 # Явная арифметическая ошибка попадает в исключение ZeroDivisionError

except ZeroDivisionError: # Попадаем в исключение сработал ZeroDivisionError

a = 10 / 2 # Операция без ошибок

print( a ) # 5.0 – при делении получаем вещественное число

As — сохраняет ошибку в переменную

В Python try except текст ошибки выводится не через класс, а через экземпляр класса. Для примера попробуем узнать, какая ошибка произошла в коде:

try:

a= 10 - '10'

except Exception:

a = Exception

print( a )

В теории мы ожидаем получить текс ошибки, но результат выполнения программы будет «». Знакомый с языком программирования человек сразу поймет, что он получил не ошибку, а ссылку на класс.

Нам необходимо создать экземпляр класса. Для этого в «except» добавляется «as». Попробуем через try except python вывести ошибку правильно:

try:

a= 10 - '10'

except Exception as Ex:

a = Ex

print( a ) # unsupported operand type(s) for -: 'int' and 'str'

Теперь мы получаем текст о сработавшем исключении с пояснением ошибки.

Finally — выполняется всегда

Finally в конструкции try – except работает так же, как, например, в более знакомом программистам if – else. Попробуем разобрать на примере:

try:

a= 10 - '1' # Явная ошибка вычитания из числа строки

# a= 10 – 1 # Пример без ошибки

except Exception as Ex:

a = Ex

finally: #Все ниже сработает при любом результате

if type (a) == int: #Если все нормально сработало и мы получили число

print( f'получен результат: {a}' )

else:

print( f'произошла ошибка: {a}' )

Блок finally выполнится при любом результате работы программы, сработало или не сработало исключение.

Else — выполняется, когда исключение не было вызвано

Если except python вывод ошибки, то else это обработка, когда ошибки не произошло. Попробуем придумать пример для демонстрации:

try:

a = 10 – 1

#a = 10 - '1' # если захотим проверить пример с ошибкой

except Exception as Ex:

a = Ex

else: # код сработает только, если никаких ошибок не было

a = a * 2
finally:

print( a )

Несколько блоков except

Чем сложнее программа, тем с большим количеством ошибок приходится встречаться. Базовый try except python 3 вывести ошибку не только одним блоком. Except может быть столько, сколько возможных исключений допустимо. Попробуем реализовать в программе:

try:

a = int( input( 'Введите число : ' ))

b = 100 / a

except ZeroDivisionError:

b = 'деление на ноль'

except ValueError:

b = 'ошибка несоответствия типов'

except Exception:

b = 'что-то пошло не так'

print( f'результат работы программы : {b}' )

В примере мы пытаемся поймать сразу два вида исключений, как весьма вероятных. Пользователь может ввести не число или ноль. На крайний случай у нас есть общий класс Exception, который поймает любую другую ошибку.

Несколько типов исключений в одном блоке except

В целом исключения определённого типа вполне возможно группировать. Здесь нет жестких ограничений. Попробуем в python try except вывести текст ошибки на примере кода:

try:

a = int(input('Введите число : '))

b = 100 / a

except (ZeroDivisionError, ValueError):

b = 'Введено недопустимое значение'

except Exception:

b = 'что-то пошло не так'

print( результат работы программы : {b}' )

В примере мы объединяем два типа ошибки, которые делают дальнейшее использование переменой недопустимым.

Raise — самостоятельный вызов исключений

Исключения возможно вызвать самостоятельно, более того, дополняя информацию о событии. Создадим пример, в котором выявим искусственное исключение:

try:

raise Exception("произошла ошибка")

except Exception as e:

print("В программе есть событие : " + str(e))

Встречаясь с raise функция или программа идет к ближайшему except Exception. Так можно не только обработать ошибку, но прописать в каком блоке кода ошибка произошла.

Как пропустить ошибку

Для программиста в python try except вывести текст ошибки важно, но не обязательно. Ошибку можно банально пропустить не пропустить без вреда для кода, рассмотрим пример:

a = 5

try:

a = a / 0

except Exception:

pass

print(a)

В примере есть ошибка, но мы просто пропускаем без вреда для кода.

Стандартные ошибки (StandardError)

С большинством ошибок, существующих в Питоне, программист никогда не встретится, многие из них встречаются в реальных проектах слишком редко. Рассмотрим, какая в python 3 обработка ошибок часто встречается.

Арифметические ошибки (ArithmeticError)

Класс, предназначенный для обработки арифметических ошибок, от него наследуются три класса:

FloatingPointError

– неудачное выполнение операций с вещественными числами. На практике редко встречается.

OverflowErro

– результат математической операции — слишком большое число, обычно это вещественное число.

ZeroDivisionError

– операция приводит к делению на ноль.

Ошибка утверждения (AssertionError)

– класс ошибки, срабатывающий если работа функции assert возвращает ложное утверждение.

Ошибка атрибута (AttributeError)

– класс ошибок, происходящих с отсутствием атрибута функций или методов.

Ошибка импорта (ModuleNotFoundError)

– ошибка, говорящая об отсутствии установленного модуля или пакета

Ошибка поиска (LookupError)

– исключение, срабатывающее при обращении к ключу или индексу несуществующему у объекта.

Ошибка ключа

– исключение срабатывает при обращении внутри словаря к несуществующему внутри него ключу.

Ошибка индекса

– срабатывает когда указанный индекс в объекте типа словарь не существует.

Ошибка памяти (MemoryError)

– в python 3 обработка ошибок срабатывающее, когда памяти для работы программы не хватает или память переполнена.

Ошибка имени (NameError)

– связана с тем, что указываемое название переменой, класса или функции не существует.

Ошибка выполнения (Runtime Error)

– класс ошибок обозначающий, что выполнение функций невозможно или произошла ошибка при выполнении.

Ошибка типа (TypeError)

– исключение, связанное с указанием или использованием неверного типа данных.

Ошибка значения (ValueError)

– исключение чаше встречающееся во время невозможности преобразования типов данных.

Пользовательские исключения в Python

Программист может создать собственный вариант исключений, наследуясь от Exception. Тут стоит обдумывать причины срабатывания и как вывести ошибку python. Код будет выглядеть примерно так:

class MyException(Exception):

pass

try:

val = int(input("Введите число: "))

if val < 0:

raise MyException("Число меньше нуля: " + str(val))

print(val + 10)

except MyException as e:

print(e)

Недостатки обработки исключений в Python

Базовые проблемы питона перекочевали в обработчик исключений, динамичность, множественное наследование, большой расход ресурсов. Также стоит отметить, что try except python в одну строку написать практически невозможно, без потери функциональности. В целом любая проблема решаема, главное — продумывать, как и когда использовать исключение.

Заключение

Не существует программиста, который способен писать код сразу, идеально, без малейших дефектов и уязвимостей. Python часто называют языком для новичков, но это не значит, что язык сделает все сам или додумает то, что не прописано. Исключения помогают избежать определённые ситуаций, не всех, но многих. Стоит помнить, что никакая дополнительная функция ошибок python не учит не совершать их вновь.

Понравилась статья? Поделить с друзьями:
  • Python try except timeout error
  • Python try except raise error
  • Python try except print error message
  • Python try except get error message
  • Python try except error code