Синтаксические ошибки и встроенные исключения в Python
Обновлено:
Мы уже знаем, что проблемы в программе могут возникать на разных этапах.
На этом уроке познакомимся с конкретными ошибками и исключениями, которые уже могли встретиться в наших программах:
ZeroDivisionError
NameError
UnboundLocalError
SyntaxError
IndentationError
TypeError
ValueError
Их названия находятся во встроенной области видимости Python, поэтому к ним можно обращаться напрямую:
print(ZeroDivisionError)
print(TypeError)
print(ValueError)
Это классы встроенных исключений Python. В дальнейшем мы научимся обрабатывать исключения и создавать собственные классы исключений на основе уже существующих.
1. ZeroDivisionError
ZeroDivisionError возникает при попытке выполнить деление или получить остаток от деления на ноль.
Самый простой пример:
result = 10 / 0
Программа завершится исключением:
ZeroDivisionError: division by zero
Такая же проблема возникает с другими операциями деления:
10 // 0
10 % 0
ZeroDivisionError внутри функции
Иногда ноль появляется не непосредственно в коде, а становится результатом вычислений:
def calculate_average(total, count, removed):
actual_count = count - removed
return total / actual_count
print(calculate_average(100, 5, 5))
Внутри функции:
actual_count = 5 - 5
получаем:
0
После этого выполняется:
100 / 0
и возникает ZeroDivisionError.
Проверка перед делением
Мы уже знаем условные конструкции, поэтому можем заранее проверить делитель:
def calculate_average(total, count, removed):
actual_count = count - removed
if actual_count == 0:
return None
return total / actual_count
Теперь:
print(calculate_average(100, 5, 5))
Результат:
None
Мы заранее предусмотрели ситуацию, в которой деление невозможно, и не допустили возникновения исключения.
Позже мы познакомимся со специальным механизмом обработки исключений.
2. NameError
NameError возникает, когда Python пытается найти имя в доступных областях видимости, но такого имени не существует.
Например:
print(product_price)
Если product_price нигде не определено:
NameError
Обращение раньше определения
print(product_price)
product_price = 1500
Python выполняет программу сверху вниз.
В момент выполнения:
print(product_price)
имя ещё не существует, поэтому возникает NameError.
Опечатка в имени
product_price = 1500
print(prodcut_price)
Переменная называется:
product_price
а обращаемся мы к:
prodcut_price
Для Python это два разных имени.
Регистр тоже имеет значение
product_price = 1500
print(Product_price)
Имена:
product_price
Product_price
разные, поэтому тоже получим NameError.
3. UnboundLocalError
С UnboundLocalError мы уже познакомились при изучении областей видимости.
Он возникает, когда функция пытается обратиться к своему локальному имени до того, как этому имени было присвоено значение.
UnboundLocalError является подклассом NameError.
Можно посмотреть цепочку наследования:
print(UnboundLocalError.mro())
Обращение до локального присваивания
value = 100
def show_value():
print(value)
value = 50
show_value()
Возникнет:
UnboundLocalError
Поскольку внутри функции есть:
value = 50
Python рассматривает value как локальное имя этой функции.
Но:
print(value)
пытается получить его значение раньше, чем оно было присвоено.
Изменение через +=
counter = 10
def increase_counter():
counter += 1
return counter
increase_counter()
Здесь операция:
counter += 1
сначала должна получить текущее значение локального counter, а затем присвоить ему новое значение.
Но локальному counter ещё ничего не было присвоено, поэтому возникает:
UnboundLocalError
4. SyntaxError
SyntaxError возникает, когда Python не может разобрать код из-за нарушения синтаксиса языка. Такая ошибка обнаруживается ещё до обычного выполнения соответствующего кода.
Например, забыли закрыть скобку:
print('Hello'
Результат:
SyntaxError
Лишняя скобка
print('Hello'))
Получим:
SyntaxError
Пропущено двоеточие
if 10 > 5
print('ok')
После условия должно находиться:
:
Без него код синтаксически неправильный.
Неправильное расположение аргументов
Мы уже знаем, что обычный позиционный аргумент нельзя ставить после именованного:
def create_report(name, age):
return f'{name}: {age}'
create_report(
name='Alex',
25,
)
Этот код нельзя корректно разобрать, поэтому возникает SyntaxError.
Как читать SyntaxError
Python обычно показывает:
- имя файла;
- номер строки;
- участок исходного кода;
- место, возле которого была обнаружена проблема;
- описание синтаксической ошибки.
Например:
File ".../main.py", line 1
print('Hello'
^
SyntaxError: '(' was never closed
5. IndentationError
В Python отступы являются частью синтаксиса.
IndentationError возникает при неправильном использовании отступов и является подклассом SyntaxError.
Нет необходимого отступа
def create_message():
return 'Hello'
После определения функции её тело должно находиться с отступом:
def create_message():
return 'Hello'
Неожиданный отступ
product_price = 1500
print(product_price)
Здесь отступ появился в месте, где Python не ожидает нового блока кода.
Это тоже может привести к:
IndentationError
Обычно мы используем четыре пробела для одного уровня отступа.
6. TypeError
TypeError возникает, когда операция или функция применяется к объекту неподходящего типа.
Упрощённо:
Python получил не тот тип данных, с которым эта операция умеет работать.
Несовместимые типы при сложении
result = '10' + 5
Слева находится:
str
справа:
int
Операция сложения в таком виде для этих объектов не определена, поэтому возникает:
TypeError
Например:
TypeError: can only concatenate str (not "int") to str
Несовместимые типы при сравнении
result = '10' > 5
Python не выполняет такое сравнение порядка между str и int.
Получим:
TypeError
Если нам действительно нужно сравнить числа, сначала необходимо привести данные к подходящему типу:
result = int('10') > 5
print(result)
Результат:
True
Неподходящий аргумент для int()
Мы можем преобразовать строку с целым числом:
number = int('10')
print(number)
Результат:
10
Но список:
int([10])
не является подходящим типом аргумента для такого преобразования.
Возникнет:
TypeError
Это хороший пример правила:
Операция получила объект неподходящего типа.
Неподходящий объект для max()
Функции:
max()
можно передать итерируемый объект:
max([10, 20, 30])
Результат:
30
Но:
max(10)
приведёт к TypeError, потому что один объект int не является итерируемым объектом.
В сообщении можно увидеть:
TypeError: 'int' object is not iterable
7. ValueError
ValueError возникает, когда тип аргумента подходит операции или функции, но само значение является недопустимым для этой операции.
Это важное отличие от TypeError.
Упрощённо:
TypeError → неподходящий тип
ValueError → тип подходит, но значение не подходит
int() и правильное значение
number = int('150')
print(number)
Строка подходит для преобразования и содержит корректную запись целого числа.
Результат:
150
int() и неподходящее значение
Теперь передадим тоже строку:
number = int('Python')
Тип аргумента:
str
подходит для int().
Но значение:
Python
невозможно интерпретировать как целое число.
Поэтому возникает:
ValueError
Например:
ValueError: invalid literal for int() with base 10: 'Python'
TypeError и ValueError на одном примере
8. Сравним два вызова int()
int([10])
Получаем:
TypeError
Потому что передан объект неподходящего типа:
list
А:
int('Python')
даёт:
ValueError
Потому что тип:
str
подходит, но конкретное значение строки нельзя преобразовать в целое число.
Это один из самых удобных примеров для понимания разницы между двумя исключениями.
ValueError в max()
Список является подходящим итерируемым объектом:
max([10, 20, 30])
Но пустой список:
max([])
не содержит ни одного элемента, который можно было бы вернуть как максимальный.
Поэтому возникает:
ValueError: max() iterable argument is empty
Здесь тип аргумента правильный:
list
но его значение — пустой список — не подходит для этого варианта вызова max().
9. Главное отличие TypeError и ValueError
Рассмотрим:
int([10])
Вопрос:
Умеет ли
int()выполнять такое преобразование из объекта этого типа?
Нет.
Получаем:
TypeError
Теперь:
int('Python')
Вопрос:
Умеет ли
int()принимать строки?
Да.
Но:
Можно ли именно эту строку преобразовать в целое число?
Нет.
Получаем:
ValueError
Официальная документация Python использует тот же общий принцип: неправильный тип аргумента относится к TypeError, а подходящий тип с неподходящим значением — к ValueError.
10. Синтаксические ошибки и исключения
Важно разделять две ситуации.
Синтаксическая ошибка
Например:
print('Hello'
Python не может нормально разобрать программу:
SyntaxError
IndentationError также относится к синтаксическим ошибкам.
Исключение во время выполнения
Например:
10 / 0
Код синтаксически правильный.
Программа начинает выполняться, но во время выполнения операции возникает:
ZeroDivisionError
Если исключение не обработано, Python показывает traceback и обычное выполнение программы прекращается.
11. Краткая таблица
| Ошибка / исключение | Основная причина |
|---|---|
ZeroDivisionError |
Деление или остаток от деления на ноль |
NameError |
Имя не найдено |
UnboundLocalError |
Локальное имя используется до присваивания значения |
SyntaxError |
Нарушен синтаксис Python |
IndentationError |
Нарушена структура отступов |
TypeError |
Операция получила объект неподходящего типа |
ValueError |
Тип подходит, но конкретное значение недопустимо |
12. Иерархия некоторых изученных исключений
Классы исключений связаны наследованием.
Например:
NameError
└── UnboundLocalError
и:
SyntaxError
└── IndentationError
Поэтому UnboundLocalError является более конкретным видом NameError, а IndentationError — более конкретным видом SyntaxError.
Позже эта иерархия станет особенно важна, когда мы научимся обрабатывать исключения и создавать собственные.
13. Как работать с незнакомой ошибкой
Не нужно пытаться запомнить все существующие исключения Python.
Если появилась незнакомая ошибка:
- прочитайте последнюю строку traceback;
- найдите название исключения;
- прочитайте описание;
- посмотрите строку кода, на которой оно возникло;
- определите причинно-следственную связь: какую операцию выполняла программа и почему эти данные для неё не подошли.
Названия стандартных исключений являются встроенными именами Python, а их описание можно найти в официальной документации.
Официальная документация
Built-in Exceptions — полный список встроенных исключений Python
Дополнительно:
Errors and Exceptions — учебный раздел документации Python
По мере изучения новых возможностей Python мы будем постепенно знакомиться и с новыми исключениями, которые могут возникать при работе с ними.