undo
search menu close

Ошибки и исключения

📅 17 апреля 2025 г. 0:59

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

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

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

Например, выведем сообщение на экран, но пропустим закрывающую скобку при вызове функции print():

print("Это сообщение написано не очень правильно"

Запустив этот код, вы увидите примерно такое сообщение о синтаксической ошибке:

Traceback (most recent call last):
  File "/home/irina/projects/task.py", line 2
    print("Это сообщение написано не очень правильно"
         ^
SyntaxError: '(' was never closed

Python выводит трассировку (англ. traceback) с информацией не только о самой ошибке, но и о её месте. Так line 2 означает, что исключение вызвал код в строке 2, а стрелочка ^ показывает что именно не так – забыта закрывающая скобка.

Если в вашем коде есть хотя бы одна синтаксическая ошибка, то он не будет запущен.

Исключения

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

Давайте напишем программу, которая запрашивает у пользователя два числа и выводит на экран результат деления первого числа на второе:

number1 = float(input("Пожалуйста, введите первое число: "))
number2 = float(input("Пожалуйста, введите второе число: "))
result = number1 / number2
print(f"{number1} / {number2} = {result}")

Допустим, пользователь ввёл числа 1 и 2, тогда программа завершится без ошибок:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 2
1 / 2 = 0.5

Но если в качестве второго числа был введён 0, то выполнение программы прервётся на строке result = number1 / number2 и будет вызвано исключение ZeroDivisionError (с англ. – Ошибка деления на нуль):

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 0
Traceback (most recent call last):
  File "/home/irina/toss a coin/Архив/Учебник.py", line 3, in <module>
    result = number1 / number2
             ~~~~~~~~^~~~~~~~~
ZeroDivisionError: float division by zero

Эта же программа может прерваться и из-за другого исключения, если пользователь вместо числа введёт строку, которую невозможно преобразовать в число:

Пожалуйста, введите первое число: Цифра 1
Traceback (most recent call last):
  File "/home/irina/toss a coin/Архив/Учебник.py", line 1, in <module>
    number1 = int(input("Пожалуйста, введите первое число: "))
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'Цифра 1'

Так как строку "Цифра 1" нельзя преобразовать в целое число, выполнение программы прерывается на первой же строке и вызывается исключение ValueError (англ. – Ошибка значения).

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

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

Давайте рассмотрим некоторые распространённые стандартные исключения.

1. NameError (с англ. – Ошибка имени) – используется объект (переменная или функция), который еще не были создан.

print(username)
# Ошибка: NameError: name 'username' is not defined

Переменной name еще не было присвоено значение, поэтому вызывается исключение.

2. TypeError (с англ. – Ошибка типа) – операция применяется к объекту не того типа:

"Яблоки" + 10
# Ошибка: TypeError: can only concatenate str (not "int") to str

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

3. ValueError (с англ. – Ошибка значения) – функции передан аргумент правильного типа, но недопустимого значения:

int("Число 25")
# Ошибка: ValueError: invalid literal for int() with base 10: 'Число'

Строку "Число 25" невозможно преобразовать в число, так как она содержит недопустимые буквенные символы.

4. ZeroDivisionError (с англ. – Ошибка деления на ноль) – попытка деления на ноль:

result = 10.5 / 0
# Ошибка: ZeroDivisionError: float division by zero

Это связано с невозможностью деления на ноль в математике.

С другими типами исключений мы познакомимся по мере изучения языка Python.

Обработка исключений

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

try:
    действия_которые_могут_привести_к_исключению
except ТипИсключения:
    действия_если_возникло_исключение

Если код внутри блока try (с англ. – попытка) вызвал исключение, тип которого совпадает с исключением, указанным после оператора except (с англ. – исключение), то выполнение блока try останавливается, и контроль переходит к соответствующему блоку except.

Давайте перепишем пример программы для деления двух чисел, используя try/except:

try:
    number1 = int(input("Пожалуйста, введите первое целое число: "))
    number2 = int(input("Пожалуйста, введите второе целое число: "))
    result = number1 / number2
    print(f"{number1} / {number2} = {result}")
except ZeroDivisionError:
    print("На ноль делить нельзя!")
except ValueError:
    print("Пожалуйста, введите целое число!")

Теперь если пользователь захочет поделить на ноль, программа всё равно продолжит работу:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 0
На ноль делить нельзя!

Также такой код обрабатывает ввод некорректного значения и исключение ValueError:

Пожалуйста, введите первое целое число: пять 
Пожалуйста, введите целое число!

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

try:
    number1 = int(input("Пожалуйста, введите первое число: "))
    number2 = int(input("Пожалуйста, введите второе число: "))
    result = number1/number2
    print(f"{number1} / {number2} = {result}")
except (ValueError, ZeroDivisionError):
     print("Упс! Что-то пошло не так!")

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

try:
    number1 = int(input("Пожалуйста, введите первое число: "))
    number2 = int(input("Пожалуйста, введите второе число: "))
    result = number1/number2
    print(f"{number1} / {number2} = {result}")
except:
    print("Упс! Что-то пошло не так!")

В таком случае блок except обрабатывает все возникающие исключения:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 0
Упс! Что-то пошло не так!

Пожалуйста, введите первое целое число: пять
Упс! Что-то пошло не так!

Но для того, чтобы понимать, какое исключение было перехвачено, с помощью конструкции Exception as e можно сохранить информацию об исключении в переменной e:

try:
    number1 = int(input("Пожалуйста, введите первое число: "))
    number2 = int(input("Пожалуйста, введите второе число: "))
    result = number1/number2
    print(f"{number1} / {number2} = {result}")
except Exception as e:
    print(f"Упс! Что-то пошло не так: {e}")

Значение переменной e может быть выведено на экран:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 0
Упс! Что-то пошло не так: division by zero

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

Необязательный блок else

Иногда вам может понадобиться выполнить какой-то код, если в блоке try не произошло исключений. Для этих целей предназначен необязательный блок else:

try:
    number1 = int(input("Пожалуйста, введите первое число: "))
    number2 = int(input("Пожалуйста, введите второе число: "))
    result = number1/number2
    print(f"{number1} / {number2} = {result}")
except ValueError:
    print("Вы должны ввести число!")
except ZeroDivisionError:
    print(f"На ноль делить нельзя!")  
else:
    print(f"Увеличим результат деления в 1000 раз: {result * 1000}")

Здесь результат деления будет увеличен в 1000 раз, если код в блоке try был выполнен полностью:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 2
1 / 2 = 0.5
Увеличим результат деления в 1000 раз: 500.0

Но если возникло исключение и был выполнен код из блока except, то код в блоке else игнорируется:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 0
На ноль делить нельзя!

Такая структура позволяет не помещать всю логику в блок try.

Необязательный блок finally

Независимо от того, возникли ли исключения, иногда нужно гарантированно выполнить некоторые операции (например, закрыть файл). Для этого служит дополнительный блок finally, который выполняется всегда, независимо от того, произошло исключение в блоке try или нет.

try:
    number1 = int(input("Пожалуйста, введите первое число: "))
    number2 = int(input("Пожалуйста, введите второе число: "))
    result = number1/number2
    print(f"{number1} / {number2} = {result}")
except ValueError:
    print("Вы должны ввести число!")
except ZeroDivisionError:
    print(f"На ноль делить нельзя!")  
else:
    print(f"Увеличим результат деления в 1000 раз: {result * 1000}")
finally:
    print("Спасибо за использование нашего калькулятора!")

Так сообщение из блока finally будет выведено на экран, как в случае корректной работы программы и отсутствия исключений:

Пожалуйста, введите первое число: 1
Пожалуйста, введите второе число: 2
1 / 2 = 0.5
Спасибо за использование нашего калькулятора!

Так и если было перехвачено какое-то исключение:

Пожалуйста, введите первое число: 1  
Пожалуйста, введите второе число: 0
На ноль делить нельзя!
Спасибо за использование нашего калькулятора!

Рекомендации по обработке исключений

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

2. Сообщайте об ошибках понятно – сообщения об ошибках должны быть информативными для пользователя или программиста, чтобы они понимали, что пошло не так и как это исправить.

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

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

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

Задания для самопроверки

1. В следующем фрагменте кода есть синтаксическая ошибка. Найдите и исправьте её.

age = int(input("Сколько тебе лет? "))
if age >= 18
  print("Ты совершеннолетний и можешь голосовать.")
else:
  print("Ты ещё несовершеннолетний, тебе нужно подождать.")
 
Ответ

2. Рассмотрите следующую трассировку ошибки:

Traceback (most recent call last):
  File "/home/user/script.py", line 5, in calculate
    result = number1 / number2
ZeroDivisionError: division by zero

На какой строке кода возникло исключение? Что является причиной возникновения ошибки?

 
Ответ

3. Напишите программу, которая запрашивает у пользователя число и пытается преобразовать его в целое число. Используйте конструкцию try/except для обработки случая, если пользователь введет не число.

 
Ответ

4. В каком случае будет выполнен блок else в конструкции try/except/else?

 
Ответ

5. Напишите программу, которая запрашивает у пользователя его возраст, и если возраст больше или равен 16, то выводит сообщение "Доступ разрешён", иначе – "Доступ запрещён".

Если введённую строку нельзя преобразовать в число, то выведите сообщение "Ошибка: пожалуйста, введите целое число"

После обработки ввода, независимо от того, было ли введенное значение корректным числом или нет, выведите сообщение "Проверка возраста завершена" .

Пример входных данных Пример выходных данных
16 Доступ разрешён
Проверка возраста завершена
14 Доступ запрещён
Проверка возраста завершена
Всегда восемнадцать Ошибка: пожалуйста, введите целое число
Проверка возраста завершена
 
Ответ
arrow_back_ios Назад
Дальше arrow_forward_ios

 💬 0 комментариев
person
email