Языки программирования

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

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

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

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

Рассмотрим пример, показывающий невозможность операции деления на ноль:
print(10 / 0)
После попытки запуска будет выведено:
Traceback (most recent call last):
File "index.py", line 1, in 
print(10 / 0)
ZeroDivisionError: division by zero
В данном случае отображается файл, а также номер строки кода, где было выброшено исключение ZeroDivisionError.

Конструкция try/except

Данная конструкция используется и в других языках программирования. В операторе try определяется потенциально опасный фрагмент кода — выполнение которого может вызвать исключения.
Затем пишется оператор except, а блок кода, следующий за ним, будет выполнен только, если система сгенерировала исключение.
Пример обработки исключения:
try:
  k = int(input("Введите целое число: "))
  print("Вы ввели: ", k)
except:
  print("Нужно было ввести целое число!!!")
input()
Если пользователь введёт число, тогда программа выведет его. А вот если ввести строку, которая не может быть преобразована в целое число, то будет исключение.

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

Разные типы исключений генерируют типы исключений. Рассмотрим самые популярные типы исключений:
  1. IOError — генерирует, если невозможно выполнить операцию ввода/вывода.
  2. IndexError — генерируется, если в последовательности не найден элемент с заданным индексом.
  3. KeyError — если в словаре не найден указанный ключ.
  4. NameError — если не найдено имя(переменной или функции).
  5. SyntaxError — если в коде обнаружена синтаксическая ошибка.
  6. TypeError — если стандартная операция применяется к объекту неподходящего типа.
  7. ValueError — если операция или функция принимает аргумент с неподходящим значением.
  8. ZeroDivisionError — если есть деление на 0.
В Python можно обработать несколько исключений. Рассмотрим пример:
try:
  a = int(input("Введите целое число: "))
  b = int(input("Введите целое число: "))
  print("a/b = ", a/b)
except ValueError:
  print("Нужно было ввести целое число!!!")
except ZeroDivisionError:
  print("На 0 делить нельзя!")
input()
В примере мы добавили исключения при неправильно введённом значении и при деление на 0. Самостоятельно проверьте работоспособность примера.

Передача аргумента исключения

В Python можно передать в программу свое ругательство, то есть сообщение об ошибки, но при этом программа не будет прервана. Это называется передачей аргумента исключения. Поправим наш прошлый пример:
try:
  a = int(input("Введите целое число: "))
  b = int(input("Введите целое число: "))
  print("a/b = ", a/b)
except ValueError:
  print("Нужно было ввести целое число!!!")
except ZeroDivisionError as e:
  print("На 0 делить нельзя!")
  print("Что сказал нам интерпретатор:")
  print(e)
input()
Вывод:

Блок else

Оператор try/except также имеет пункт else. Он работает только в том случае, если в вашем коде нет ни единой ошибки. Исправим наш прошлый пример используя else:
try:
  k = int(input("Введите целое число: "))
except:
  print("Нужно было ввести целое число!!!")
else:
  print("Вы ввели: ", k)
input()
В try принято помещать код, который может сгенерировать исключение. В else можно поместить код, который будет выполнен, если все нормально и исключение не было сгенерировано.

Оператор finally

Также у блока except есть еще один необязательный блок finally, который сработает независимо от того, выполнился код с ошибками или без. Пример:
try:
   a = int(input("Введите первое число: "))
   b = int(input("Введите второе число: "))
   print("a/b = ", a/b)
except ValueError:
   print("Это не число!")
except ZeroDivisionError:
   print("На ноль делить нельзя!")
except:
   print("Неожиданная ошибка.")
else:
   print("Код выполнился без ошибок")
finally:
   print("Я выполняюсь в любом случае!")
input()
Вывод программы:
Используя обработку исключительных, можно защитить программу от взлома, непредвиденного поведения и в будущем получить детальную информацию по логическим ошибкам, содержащимся в ней.

Видео по теме «Обработка исключений»:

Программа «Тесты 2.0»

В статье «Условный оператор IF» мы создавали программу «Тесты». В этой статье мы продолжим разрабатывать данную программу.
Сделаем так, чтобы наши вопросы и ответы хранились в списках. Также у нас будет переменная n, содержащая количество вопросов. Мы с легкостью сможем изменять количество вопросов. В нашей новой версии сделаем защиту нашей программы с помощью конструкция try/except.

Программа «Редактор тестов»

Программа «Редактор тестов» будет записывать вопросы и ответы в файл «test.dat» с помощью модуля pickle.
Преимущество такого подхода в том, что тестируемый не сможет открыть Python-файл программы и просмотреть список правильных ответов. Ведь в «test.dat» все данные хранятся в двоичном виде. Рассмотрим листинг программы:
import pickle

questions = ["""
      Сколько бит в одном байте
      1) 8
      2) 6
      3) 4
      4) 2
      """,
      """
      Сколько байт в одном килобайте
      1) 1000
      2) 1024
      3) 1048
      4) 256
      """,
      """
      Компания-разработчик Windows
      1) Apple
      2) Melkosoft
      3) Cybersoft
      4) Microsoft
      """,
      """
      Компания-разработчик MacOS
      1) Apple
      2) Microsoft
      3) Fredd
      4) google
      """,
      """
      Символом какой операционной системы является пингвин
      1) Linux
      2) FreeBSD
      3) MacOS
      4) Windows
      """]
      
answers = [1, 2, 4, 1, 1]

datafile = open("test.dat", "wb")

pickle.dump(questions, datafile)
pickle.dump(answers, datafile)

datafile.close()

input("Файл test.dat создан!")
Рекомендуется изучить статью «Файлы. Работа с файлами в Python» для лучшего понимания работы с файлами в Python.

В результате работы программы будет создан файл «test.dat» с законсервированными списками вопросов и правильных ответов.

Файл с вопросами и ответами создан, а теперь продолжим разработку программы «Тесты». Листинг программы:
import pickle

mark = 0

print("*" * 10, "Тесты 2.0", "*" * 10)

# загружаем списки вопросов и ответов
try:
  datafile = open("test.dat", "rb")
except:
  print("Ошибка при загрузке вопросов!")
else:
  
  questions = pickle.load(datafile)
  answers = pickle.load(datafile)
  datafile.close()
  n = len(answers) # количество вопросов и ответов
  i = 0
  for i in range(0, n):
      print(questions[i])
      try:
        a = int(input("Ваш ответ: "))
        if a == answers[i]:
           mark = mark + 1
           print("Правильно!")
        else:
           print("Неправильно!")
      except:
           print("Нужно было ввести число. Ответ засчитан как неправильный!")
  print("Вы правильно ответили на ", mark, "вопросов из ", n)
  
input("Нажмите Enter для выхода")
Подробно рассмотрим код, написанной программы. Вопросы у нас выводятся в цикле for. В цикле мы выводим вопрос из списка «questions», далее читаем ответ, если ответ совпадает с правильным (которые хранятся в списке «answers»), то увеличиваем переменную «mark» и выводим сообщение «Правильно!». В противном случае «Неправильно!».

В коде мы используем обработку исключений — вдруг файл «test.dat» будет отсутствовать. Если же все нормально (блок else), мы загрузим списки вопросов и ответов, определим количество вопросов.

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

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

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