Обработка ошибок
В программировании есть две базовые категории ошибок:
- Синтаксические ошибки, которые не дают программе выполниться
- Ошибки времени выполнения, которые останавливают выполнение
Ошибки категории 1 обычно легко исправить, потому что интерпретатор Python указывает место ошибки при попытке выполнить программу. Распространенные синтаксические ошибки включают отсутствие двоеточия в конце заголовочной строки или отсутствие закрывающей кавычки в конце строки.
Ошибки категории 2 бывает сложнее заметить, потому что они могут возникать только в определенный момент выполнения программы и только при определенных обстоятельствах. Программа может прекрасно работать в большинстве ситуаций, но останавл иваться из-за ошибки в конкретном граничном случае. Теперь мы сосредоточимся на обработке ошибок такого типа.
Проверка ввода
Многие ошибки, возникающие во время выполнения программы, связаны с недопустимым вводом. Некоторые примеры:
- отсутствующие или пустые значения ввода в обязательных полях, например пустые строки, когда длина строки критична
- отрицательные значения там, где принимаются только положительные, например -15 как количество ингредиента в рецепте
- отсутствующие файлы или опечатки в именах файлов
- слишком маленькие или слишком большие значения, например при работе с датами и временем
- недопустимые индексы, например попытка обратиться к индексу 3 в строке "hey"
- значения неправильного тип а, например строки, когда ожидаются целые числа
К счастью, мы как программисты можем подготовиться к большинству ошибок. Рассмотрим программу, которая спрашивает у пользователя возраст и убеждается, что это допустимое число (в данном случае между 0 и 150):
age = int(input("Please type in your age: "))
if age >= 0 and age <= 150:
print("That is a fine age")
else:
print("This is not a valid age")Please type in your age: 25 That is a fine age
Please type in your age: -3 This is not a valid age
Пока пользователь вводит целое число, наша проверка ввода, кажется, работает хорошо. Но что если он введет строку?
Please type in your age: twenty-three ValueError: invalid literal for int() with base 10: 'twenty-three'
Функция int не может разобрать входную строку twenty-three как допустимое целое число. Выполнение останавливается, и выводится сообщение об ошибке выше.
Исключения
Ошибки, которые возникают, когда программа уже выполняется, называются исключениями. К исключениям можно подготовиться и обработать их так, чтобы выполнение продолжилось, несмотря на их возникновение.
Обработка исключений в Python выполняется с помощью операторов try и except. Идея в том, что если что-то внутри блока try вызывает исключение, Python проверяет, есть ли соответствующий блок except. Если такой блок существует, он выполняется, а программа затем продолжается так, будто ничего не произошло.
Изменим пример выше так, чтобы программа была готова к исключению ValueError:
try:
age = int(input("Please type in your age: "))
except ValueError:
age = -1
if age >= 0 and age <= 150:
print("That is a fine age")
else:
print("This is not a valid age")Please type in your age: twenty-three This is not a valid age
Мы можем использовать блок try, чтобы отметить, что код внутри блока может вызвать ошибку. В операторе except сразу после блока указывается соответствующая ошибка. В примере выше мы обработали только исключение ValueError. Если бы у исключения была другая причина, выполнение все равно остановилось бы, несмотря на блоки try и except.
В примере выше, если ошибка поймана, значение age устанавливается в -1. Это недопустимое входное значение, для которого мы уже запрограммировали поведение, поскольку программа ожидает, что возраст пользователя больше 0.
В следующем примере есть функция read_integer, которая просит пользователя ввести целое число, но также готова к недопустимому вводу. Функция продолжает спрашивать целые числа, пока пользователь не введет допустимое значение.
def read_integer():
while True:
try:
input_str = input("Please type in an integer: ")
return int(input_str)
except ValueError:
print("This input is invalid")
number = read_integer()
print("Thank you!")
print(number, "to the power of three is", number**3)Please type in an integer: three This input is invalid Please type in an integer: aybabtu This input is invalid Please type in an integer: 5 Thank you! 5 to the power of three is 125
Иногда достаточно поймать исключения с помощью структуры try-except, ничего с ними не делая. То есть в блоке except можно просто игнорировать ситуацию.
Если бы мы изменили пример выше так, чтобы принимать только целые числа меньше 100, результаты могли бы выглядеть так:
def read_small_integer():
while True:
try:
input_str = input("Please type in an integer: ")
number = int(input_str)
if number < 100:
return number
except ValueError:
pass # this command doesn't actually do anything
print("This input is invalid")
number = read_small_integer()
print(number, "to the power of three is", number**3)Please type in an integer: three This input is invalid Please type in an integer: 1000 This input is invalid Please type in an integer: 5 Thank you! 5 to the power of three is 125
Теперь блок except содержит только команду pass, которая ничего не делает. Python не допускает пустые блоки, поэтому эта команда необходима.
Типичные ошибки
Ниже подборка типичных ошибок, с которыми вы, скорее всего, столкнетесь, вместе с ситуациями, где они могут возникать.
ValueError
Эта ошибка часто возникает, когда аргумент, переданный функции, каким-то образом недопустим. Например, вызов функции float("1,23") вызывает ошибку, потому что в Python дробная часть всегда отделяется точкой, а здесь используется запятая.
TypeError
Эта ошибка возникает, когда значение имеет неправильный тип. Например, вызов функции len(10) вызывает TypeError, потому что функция len требует значение, длину которого можно вычислить, например строку или список.
IndexError
Э та распространенная ошибка возникает при попытке сослаться на индекс, которого не существует. Например, выражение "abc"[5] вызывает IndexError, потому что у этой строки нет индекса 5.
ZeroDivisionError
Как следует из названия, эта ошибка возникает при попытке делить на ноль, что, как мы знаем из математики, всегда плохая идея. Например, если мы пытаемся определить среднее арифметическое значений в списке по формуле sum(my_list) / len(my_list), но длина нашего списка равна нулю, возникнет эта ошибка.
Исключения при работе с файлами
Некоторые распространенные ошибки при работе с файлами: FileNotFoundError (при попытке обратиться к файлу, которого не существует), io.UnsupportedOperation (при попытке выполнить операцию с файлом, которая не поддерживается режимом, в котором файл открыт) или PermissionError (у программы нет необходимых прав доступа к файлу).