Обработка ошибок ввода python

I don’t know why I never thought of this before… but I’m wondering if there’s a neater/shorter/more efficient manner of error handling a user input. For example, if I ask the user to enter either «hello» or «goodbye», and they type something else, I need it to tell the user it’s wrong and ask again.

For all of coding I’ve ever done, this is how I’ve done it (typically the question is better):

choice = raw_input("hello, goodbye, hey, or laters? ") 

while choice not in ("hello","goodbye","hey","laters"):

   print "You typed something wrong!"

   choice = raw_input("hello,goodbye,hey,or laters? ")

Is there a smarter way of doing this? Or should I just stick with how I’ve had it? This is the method I use for all languages I’ve written in.

SecretAgentMan's user avatar

asked Oct 16, 2013 at 15:54

user2869231's user avatar

For a simple script, the way you have it is fine.

For a more complex system, you’re effectivey writing your own parser.

def get_choice(choices):
  choice = ""
  while choice not in choices:
      choice = raw_input("Choose one of [%s]:" % ", ".join(choices))
  return choice

choice = get_choice(["hello", "goodbye", "hey", "laters"])

answered Oct 16, 2013 at 16:04

Christian Ternus's user avatar

6

If you modify your code to always enter the while loop, you only have to have the raw_input on one line.

while True:
    choice = raw_input("hello, goodbye, hey, or laters? ")
    if choice in ("hello","goodbye","hey","laters"):
        break
    else:
        print "You typed something wrong!"

answered Oct 16, 2013 at 16:01

SethMMorton's user avatar

SethMMortonSethMMorton

45.9k12 gold badges65 silver badges86 bronze badges

1

You can do it with recursion

>>> possible = ["hello","goodbye","hey"]
>>> def ask():
...     choice = raw_input("hello,goodbye,hey,or laters? ")
...     if not choice in possible:
...         return ask()
...     return choice
... 
>>> ask()
hello,goodbye,hey,or laters? d
hello,goodbye,hey,or laters? d
hello,goodbye,hey,or laters? d
hello,goodbye,hey,or laters? hello
'hello'
>>> 

answered Oct 16, 2013 at 16:03

Foo Bar User's user avatar

Foo Bar UserFoo Bar User

2,4013 gold badges20 silver badges26 bronze badges

4

That’s how you do it.
Having the options in a list might be prettier though depending on how you’re using it.

options = ["hello", "goodbye", "hey", "laters"]
while choice not in options:
    print "You typed something wrong!"

answered Oct 16, 2013 at 16:00

Mattias's user avatar

MattiasMattias

4513 silver badges13 bronze badges

3

Уровень сложности
Средний

Время на прочтение
8 мин

Количество просмотров 14K

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

  • Что такое обработка исключений?

  • Разница между оператором if и обработкой исключений.

  • Использование разделов else и finally блока try-except для организации правильного обращения с ошибками.

  • Определение пользовательских исключений.

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

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

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

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

Различия между оператором if и обработкой исключений

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

Оператор if — это базовый строительный элемент структурного программирования. Этот оператор проверяет условие и выполняет различные блоки кода, основываясь на том, истинно проверяемое условие или ложно. Вот пример:

temperature = int(input("Please enter temperature in Fahrenheit: "))
if temperature > 100:
    print("Hot weather alert! Temperature exceeded 100°F.")
elif temperature >= 70:
    print("Warm day ahead, enjoy sunny skies.")
else:
    print("Bundle up for chilly temperatures.")

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

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

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

# Определение функции, которая пытается поделить число на ноль
def divide(x, y):
    result = x / y
    return result
# Вызов функции divide с передачей ей x=5 и y=0
result = divide(5, 0)
print(f"Result of dividing {x} by {y}: {result}")

Вывод:

Traceback (most recent call last):
  File "<stdin>", line 8, in <module>
ZeroDivisionError: division by zero attempted

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

Вышеописанное исключение можно обработать, обернув вызов функции divide в блок try-except:

# Определение функции, которая пытается поделить число на ноль
def divide(x, y):
    result = x / y
    return result
# Вызов функции divide с передачей ей x=5 и y=0
try:
    result = divide(5, 0)
    print(f"Result of dividing {x} by {y}: {result}")
except ZeroDivisionError:
    print("Cannot divide by zero.")

Вывод:

Cannot divide by zero.

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

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

Использование разделов else и finally блока try-except для организации правильного обращения с ошибками

При работе с исключениями в Python рекомендуется включать в состав блоков try-except и раздел else, и раздел finally. Раздел else позволяет программисту настроить действия, производимые в том случае, если при выполнении кода, который защищают от проблем, не было вызвано исключений. А раздел finally позволяет обеспечить обязательное выполнение неких заключительных операций, вроде освобождения ресурсов, независимо от факта возникновения исключений (вот и вот — полезные материалы об этом).

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

Использование разделов else и finally позволяет поступить именно так — обработать данные обычным образом в том случае, если исключений не возникло, либо обработать любые исключения, но, как бы ни развивались события, в итоге закрыть файл. Без этих разделов код страдал бы уязвимостями в виде утечки ресурсов или неполной обработки ошибок. В результате оказывается, что else и finally играют важнейшую роль в создании устойчивых к ошибкам и надёжных программ.

try:
    # Открытие файла в режиме чтения
    file = open("file.txt", "r")
    print("Successful opened the file")
except FileNotFoundError:
    # Обработка ошибки, возникающей в том случае, если файл не найден
    print("File Not Found Error: No such file or directory")
    exit()
except PermissionError:
    # Обработка ошибок, связанных с разрешением на доступ к файлу
    print("Permission Denied Error: Access is denied")
else:
    # Всё хорошо - сделать что-то с данными, прочитанными из файла
    content = file.read().decode('utf-8')
    processed_data = process_content(content)
    
# Прибираемся после себя даже в том случае, если выше возникло исключение
finally:
    file.close()

В этом примере мы сначала пытаемся открыть файл file.txt для чтения (в подобной ситуации можно использовать выражение with, которое гарантирует правильное автоматическое закрытие объекта файла после завершения работы). Если в процессе выполнения операций файлового ввода/вывода возникают ошибки FileNotFoundError или PermissionError — выполняются соответствующие разделы except. Здесь, ради простоты, мы лишь выводим на экран сообщения об ошибках и выходим из программы в том случае, если файл не найден.

В противном случае, если в блоке try исключений не возникло, мы продолжаем работу, обрабатывая содержимое файла в ветви else. И наконец — выполняется «уборка» — файл закрывается независимо от возникновения исключения. Это обеспечивает блок finally (подробности смотрите здесь).

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

Определение пользовательских исключений

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

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

Вот пример определения пользовательского исключения, названного InvalidEmailAddress:

class InvalidEmailAddress(ValueError):
    def __init__(self, message):
        super().__init__(message)
        self.msgfmt = message

Это исключение является наследником ValueError. Его конструктор принимает необязательный аргумент message (по умолчанию он устанавливается в значение invalid email address).

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

def send_email(address):
    if isinstance(address, str) == False:
        raise InvalidEmailAddress("Invalid email address")
# Отправка электронного письма

Теперь, если функции send_email() будет передана строка, содержащая неправильно оформленный адрес, то, вместо сообщения стандартной ошибки TypeError, будет выдано настроенное заранее сообщение об ошибке, которое чётко указывает на возникшую проблему. Например, это может выглядеть так:

>>> send_email(None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/project/main.py", line 8, in send_email
    raise InvalidEmailAddress("Invalid email address")
InvalidEmailAddress: Invalid email address

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

Вот несколько рекомендаций, относящихся к обработке ошибок в Python:

  1. Проектируйте код в расчёте на возможное возникновение ошибок. Заранее планируйте устройство кода с учётом возможных сбоев и проектируйте программы так, чтобы они могли бы достойно обрабатывать эти сбои. Это означает — предугадывать возможные пограничные случаи и реализовывать подходящие обработчики ошибок.

  2. Используйте содержательные сообщения об ошибках. Сделайте так, чтобы программа выводила бы, на экран, или в файл журнала, подробные сообщения об ошибках, которые помогут пользователям понять — что и почему пошло не так. Старайтесь не применять обобщённые сообщения об ошибках, наподобие Error occurred или Something bad happened. Вместо этого подумайте об удобстве пользователя и покажите сообщение, в котором будет дан совет по решению проблемы или будет приведена ссылка на документацию. Постарайтесь соблюсти баланс между выводом подробных сообщений и перегрузкой пользовательского интерфейса избыточными данными.

  3. Минимизируйте побочные эффекты. Постарайтесь свести к минимуму последствия сбойных операций, изолируя проблемные разделы кода посредством конструкции try-finally или try с использованием with. Сделайте так, чтобы после выполнения кода, было ли оно удачным или нет, обязательно выполнялись бы «очистительные» операции.

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

  5. Регулярно выполняйте рефакторинг кода. Выполняйте рефакторинг фрагментов кода, подверженных ошибкам, чтобы улучшить их надёжность и производительность. Постарайтесь, чтобы ваша кодовая база была бы устроена по модульному принципу, чтобы её отдельные части слабо зависели бы друг от друга. Это позволяет независимым частям код самостоятельно эволюционировать, не оказывая негативного воздействия на другие его части.

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

Итоги

Написание кода обработки ошибок — это неотъемлемая часть индустрии разработки ПО, и, в частности — разработки на Python. Это позволяет разработчикам создавать более надёжные и стабильные программы. Следуя индустриальным стандартам и рекомендациям по обработке исключений, разработчик может сократить время, необходимое на отладку кода, способен обеспечить написание качественных программ и сделать так, чтобы пользователям было бы приятно работать с этими программами.

О, а приходите к нам работать? 🤗 💰

Мы в wunderfund.io занимаемся высокочастотной алготорговлей с 2014 года. Высокочастотная торговля — это непрерывное соревнование лучших программистов и математиков всего мира. Присоединившись к нам, вы станете частью этой увлекательной схватки.

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

Сейчас мы ищем плюсовиков, питонистов, дата-инженеров и мл-рисерчеров.

Присоединяйтесь к нашей команде.

В данной статье мы рассмотрим основные конструкции работы с исключениями в Python: try, except, else и finally. Мы рассмотрим, как использовать эти конструкции для обработки исключений, как правильно выбирать тип исключения, какие существуют способы обработки нескольких исключений и многое другое. Если вы хотите узнать больше о том, как правильно обрабатывать ошибки в Python, то эта статья для вас!

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

Обработка исключений в Python осуществляется с помощью блока try-except. Код, который может вызвать исключение, помещается в блок try, а код, который обрабатывает исключение, помещается в блок except. Кроме того, можно использовать блок else для выполнения кода в случае, если исключение не было вызвано, и блок finally для выполнения кода независимо от того, было вызвано исключение или нет.

Синтаксис блока try-except выглядит следующим образом:

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

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

Пример:

try:
    # блок кода, который может вызвать исключение
except Имя_исключения as e:
    # код обработки исключения
    print(e) # вывод информации об исключении
else:
    # блок кода, который будет выполнен, если исключение не было вызвано
finally:
    # блок кода, который будет выполнен в любом случае

В блоке except можно использовать переменную для получения информации об исключении. Эта переменная обычно называется «e» или «exception», но может иметь любое другое имя. В примере мы выводим информацию об исключении с помощью функции print().

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

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

Для обработки исключений в Python используется конструкция try-except. Код, который может вызвать исключение, помещается в блок try, а код для обработки исключения помещается в блок except.

Пример:

try:
    # блок кода, который может вызвать исключение
    x = 1 / 0
except ZeroDivisionError:
    # блок кода для обработки исключения
    print("Деление на ноль!")

В этом примере, если выполнение кода в блоке try вызовет исключение ZeroDivisionError (при делении на ноль), то программа перейдет в блок except и выполнит код внутри него.

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

Пример:

try:
    # блок кода, который может вызвать исключение
    x = int("не число")
except ValueError:
    # блок кода для обработки исключения ValueError
    print("Неверный формат числа")
except:
    # блок кода для обработки всех других исключений
    print("Произошла ошибка")
finally:
    # блок кода, который будет выполнен в любом случае
    print("Конец программы")

В этом примере, если выполнение кода в блоке try вызовет исключение ValueError (при попытке преобразовать строку «не число» в число), то программа перейдет в блок except, который обработает это исключение. Если произойдет любое другое исключение, программа перейдет в блок except без указания типа исключения. В любом случае, программа выполнит код в блоке finally, который будет выполнен независимо от того, было или нет исключение.

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

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

Синтаксис raise в Python прост:

raise <ExceptionType>(<optional message>)

ExceptionType — это класс исключения, который может быть встроенным в Python, либо собственным классом, унаследованным от класса Exception. <optional message> — это строка, которая может содержать сообщение об ошибке, которое будет доступно в объекте исключения.

Пример:

def divide(x, y):
    if y == 0:
        raise ZeroDivisionError("Деление на ноль невозможно")
    else:
        return x / y

try:
    result = divide(10, 0)
except ZeroDivisionError as e:
    print(e)

В этом примере функция divide проверяет, что второй аргумент не равен нулю. Если он равен нулю, функция вызывает исключение ZeroDivisionError с соответствующим сообщением об ошибке. Затем функция используется в блоке try-except, где перехватывается исключение и выводится его сообщение.

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

Основные стандартные исключения в Python

Перечислим основные исключения в Python, сгруппированные по своему назначению:

Исключения общего назначения

  • Exception — базовый класс для всех исключений в Python.
  • StopIteration — возникает, когда итератор больше не имеет значений.
  • GeneratorExit — возникает, когда вызывается метод generator.close().
  • SystemExit — возникает, когда вызывается функция sys.exit().
  • KeyboardInterrupt — возникает, когда пользователь нажимает комбинацию клавиш, которая прерывает выполнение программы (обычно это Ctrl+C).

Исключения для ошибок ввода/вывода

  • IOError — возникает, когда происходит ошибка ввода/вывода (например, если файл не найден).
  • OSError — возникает, когда происходит системная ошибка ввода/вывода.
  • EOFError — возникает, когда достигнут конец файла (EOF) и функция input() не может считать больше данных.

Исключения для ошибок типов данных

  • TypeError — возникает, когда операция или функция применяется к объекту неправильного типа.
  • ValueError — возникает, когда операция или функция применяется к объекту с правильным типом, но неправильным значением (например, если функция int() вызывается с аргументом, который не может быть преобразован в целое число).

Исключения для ошибок арифметических операций

  • ZeroDivisionError — возникает, когда попытка деления на ноль.
  • ArithmeticError — базовый класс для исключений, связанных с арифметическими операциями.
  • OverflowError — возникает, когда результат арифметической операции слишком велик для представления в виде числа определенного типа.

Исключения для ошибок импорта модулей

  • ImportError — возникает, когда не удалось импортировать модуль или его атрибут.
  • ModuleNotFoundError — возникает, когда модуль не может быть найден при попытке его импортировать.

Исключения для ошибок работы с файлами

  • FileNotFoundError — возникает, когда файл не найден при попытке его открытия.
  • PermissionError — возникает, когда у пользователя нет прав на выполнение операции с файлом.

Подробное описание всех классов встроенных исключений в Python смотрите в официальной документации.

Cобственные исключения в Python

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

Пример создания собственного исключения:

class MyCustomException(Exception):
    pass

В данном примере мы создаем новый класс исключения MyCustomException, который наследуется от класса Exception. Внутри класса мы не определяем никаких методов или свойств, так как наследуем их от класса Exception.

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

def my_function(x):
    if x < 0:
        raise MyCustomException("x не может быть отрицательным")
    return x**2

try:
    result = my_function(-5)
except MyCustomException as e:
    print(e)
else:
    print(result)

В данном примере мы создаем функцию my_function, которая вызывает собственное исключение MyCustomException, если переданный ей аргумент отрицательный. Затем мы используем эту функцию в блоке try-except, где перехватываем собственное исключение и выводим его сообщение об ошибке. Если исключение не было вызвано, выводим результат работы функции.

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

Примеры использования исключений try-except

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

  1. Обработка исключений при работе с файлами

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

try:
    with open('file.txt', 'r') as f:
        data = f.read()
        print(data)
except FileNotFoundError:
    print('Файл не найден')
  1. Обработка исключений при делении на ноль

В этом примере мы попытаемся поделить число на ноль, что приведет к возникновению исключения ZeroDivisionError.

try:
    result = 10 / 0
    print(result)
except ZeroDivisionError:
    print('Деление на ноль')
  1. Обработка исключений при работе с API

В этом примере мы попытаемся получить данные из API. Если запрос не удалось выполнить по какой-либо причине (например, отсутствие подключения к интернету), будет вызвано исключение ConnectionError.

import requests

try:
    response = requests.get('https://api.example.com/data')
    data = response.json()
    print(data)
except ConnectionError:
    print('Нет подключения к интернету')
  1. Обработка исключений при работе с базами данных

В этом примере мы попытаемся выполнить запрос к базе данных. Если запрос не выполнится по какой-либо причине (например, ошибка синтаксиса), будет вызвано исключение DatabaseError.

import sqlite3

try:
    conn = sqlite3.connect('example.db')
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM table')
    data = cursor.fetchall()
    print(data)
except sqlite3.DatabaseError:
    print('Ошибка при работе с базой данных')
finally:
    conn.close()

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

Советы по работе с блоком try-except

Ниже приведены несколько советов по работе с блоком try-except в Python:

  • Используйте блок try-except только для обработки исключений, которые вы ожидаете. Не ловите все исключения без разбора, так как это может затруднить отладку и привести к скрытию других ошибок.
  • Включайте в блок try только тот код, который может вызвать исключение. Таким образом, вы сможете обработать ошибку на месте, где она произошла, и предотвратить нежелательные побочные эффекты.
  • Если вы используете несколько блоков except, разместите более специфические блоки except перед менее специфическими. Таким образом, вы сможете обработать ошибку наиболее точным способом и избежать ненужных проверок.
  • Используйте блок else для кода, который должен выполняться только в том случае, если блок try завершается без возникновения исключений. Это может быть полезно, например, для закрытия файлов или соединений после выполнения кода.
  • Используйте блок finally для кода, который должен выполняться в любом случае, независимо от того, возникло исключение или нет. Например, блок finally может использоваться для освобождения ресурсов, которые были захвачены в блоке try.
  • При возникновении исключения используйте методы объекта исключения для получения дополнительной информации, такой как тип исключения или сообщение об ошибке. Это может помочь в отладке и понимании причин ошибок.

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

Заключение

В данной статье мы рассмотрели синтаксис конструкции try-except, виды стандартных исключений, а также привели несколько примеров использования этой конструкции в различных ситуациях.

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

На чтение 13 мин Просмотров 4.2к. Опубликовано

Содержание

  1. Введение в тему
  2. Что такое исключения
  3. Перехват исключений
  4. Несколько блоков except
  5. Вложенные блоки и else
  6. Finally
  7. Управление исключениями
  8. Пользовательские исключения
  9. Запись в лог
  10. Иерархия исключений

Введение в тему

Зачастую возникают ситуации, когда программа или скрипт работают не так, как задумывал программист. Чаще всего это бывает из-за ввода неожиданных данных. Для обработки таких ситуаций в языке программирования Python есть конструкция try except else finally. Это называется обработкой исключений и позволяет контролировать аварийные случаи. Об этом мощном инструменте мы и поговорим в данном уроке.

Что такое исключения

Работа программиста во многом связана с возникающими в коде ошибками. Их приходится находить и исправлять. Особенно опасны так называемые гейзенбаги – ошибки, которые сложно воспроизвести. Так же существуют скрытые ошибки, их ещё можно назвать логическими. Ещё есть ошибки, которые и вовсе не зависят от программы. Представьте, у Вас есть программа-скрапер, которая автоматически скачивает картинки из соцсети. Заходит она на очередную страницу… А сервер сети поломался. Программа выдаст ошибку.

Если говорить именно о Питоне, то сложность ещё и в том, что это не компилируемый, а интерпретируемый язык, то есть код выполняется «на лету», строка за строкой. Это означает, что у Пайтон-программиста нет возможности отловить ошибки на этапе компиляции. Ещё одна сложность заключается в том, что Python – язык со строгой, но динамической типизацией. Частично это решается в последних версиях языка средством под названием «аннотирование типов», но полностью проблемы не устраняет.

И так, существуют следующие виды ошибок:

  • Синтаксические – когда программист нарушает правила самого языка, к примеру, допускает опечатку в ключевом слове;
  • Логические – когда в коде используется не верная логика;
  • Ввода – когда программист предполагал от пользователя ввода одних данных, а введены другие. К примеру, создатель сайта задумывал, что число в форме будет указано с использованием точки в качестве разделителя, а пользователь ввёл «3,14». Именно этот вид ошибок – излюбленная лазейка хакеров.

Синтаксические ошибки – самые простые, поскольку интерпретатор сам сообщит Вам о них при попытке запустить скрипт.

Простой пример, напечатали команду print с большой буквы:


Print('Hello World!')
# Вывод

Traceback (most recent call last):

File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 1, in <module>

Print('Hello World!')

NameError: name 'Print' is not defined

 

Process finished with exit code 1

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


from random import randint

random_list = 5
sorted_list = []
for i in range(random_list):
sorted_list.append(randint(1, 99))
print(sorted_list)

for i in range(random_list - 1):
for j in range(random_list - i - 1):
if sorted_list[j] > sorted_list[j + 1]:
sorted_list[j] = sorted_list[j + 1]

print(sorted_list)
# Вывод:

 

[95, 57, 16, 29, 82]

[16, 16, 16, 29, 82]

В этом примере программист хотел сделать сортировку пузырьком, но допустил ошибку. А Вы сможете её найти?

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


x_var = input('Введите число и мы его разделим на 10 \n')
print('Результат деления:', float(x_var) / 10)
# Вывод:

 

Введите число и мы его разделим на 10

3,14

Traceback (most recent call last):

File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 2, in <module>

print('Результат деления:', float(x_var) / 10)

ValueError: could not convert string to float: '3,14'

Как вы видите, интерпретатор «выбрасывает» исключение «ValueError» — ошибка значения и останавливает выполнение кода.

Перехват исключений

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


x_var = input('Введите число и мы его разделим на 10 \n')
try:
print('Результат деления:', float(x_var) / 10)
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
print('Программа завершена')
# Вывод:

Введите число и мы его разделим на 10

3,14

Вы ввели число с запятой, а надо с точкой

Программа завершена

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

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

Можно использовать несколько блоков except и обрабатывать в каждом блоке отдельный вид ошибки. Немного перепишем программу из предыдущего примера:


x_var = input('Введите число и мы разделим на него 10 \n')
try:
print('Результат деления:', 10 / float(x_var))
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
print('Программа завершена')
# Вывод:

Введите число и мы разделим на него 10

0

Вы ввели ноль, но на него делить нельзя

Программа завершена

Хорошей практикой является написание сперва блоков для конкретных ошибок, а затем для общих случаев, поскольку всех ситуаций не предусмотреть:


x_var = input('Введите число и мы разделим на него 10 \n')
try:
Print('Результат деления:', 10 / float(x_var))
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
except:
print('Не знаю что, но что-то точно пошло не так')
print('Программа завершена')
# Вывод:

Введите число и мы разделим на него 10

10

Не знаю что, но что-то точно пошло не так

Программа завершена

Вложенные блоки и else

Блоки try-except можно вкладывать друг в друга, если в этом есть необходимость.

Здесь же мы используем блок else. Этот блок должен содержать код, который выполнится если не возникнет исключений.


x_var = input('Введите число и мы разделим на него 10 \n')
try:
result = 10 / float(x_var)
try:
print('Результат деления:', result)
except:
print('Не знаю что, но что-то точно пошло не так')
else:
print('Полёт нормальный')
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
else:
print('Программа выполнена без ошибок')
print('Программа завершена')
# Вывод:

Введите число и мы разделим на него 10

10

Результат деления: 1.0

Полёт нормальный

Программа выполнена без ошибок

Программа завершена

Кстати, здесь допущена логическая ошибка. Найдёте?

Finally

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


try:
result = 10 / float(x_var)
try:
Print('Результат деления:', result)
except:
print('Не знаю что, но что-то точно пошло не так')
else:
print('Полёт нормальный')
except ValueError:
print('Вы ввели число с запятой, а надо с точкой')
except ZeroDivisionError:
print('Вы ввели ноль, но на него делить нельзя')
finally:
print('Программа завершена')
# Вывод:

Введите число и мы разделим на него 10

10

Не знаю что, но что-то точно пошло не так

Программа завершена

Управление исключениями

В Пайтоне есть возможность создавать свои виды исключений. Ниже мы рассмотрим как это делать, а ещё такую важную вещь как логгирование.

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

В Python есть ключевое слово raise. Нужно оно для того чтоб самостоятельно вызывать исключения:


raise Exception("Моя ошибка")
# Вывод:

Traceback (most recent call last):

File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 1, in <module>

raise Exception("Моя ошибка")

Exception: Моя ошибка

Такие ошибки тоже можно ловить в try и обрабатывать в except:


x_var = float(input('Введите число\n'))
try:
if x_var > 10:
raise Exception()
except:
print('Что-то пошло не так. Возможно, число слишком большое')
# Вывод:

Введите число

11

Что-то пошло не так. Возможно, число слишком большое

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


class MyException(Exception):
def __str__(self):
return 'Число слишком большое'

x_var = float(input('Введите число\n'))
try:
if x_var > 10:
raise MyException()
except MyException:
print(MyException())
# Вывод:

Введите число

11

Число слишком большое

Так же, текст ошибки можно передавать переопределяя родительский атрибут message:


class MyException(Exception):
def __init__(self):
self.message = 'Число слишком большое'
super().__init__(self.message)

x_var = float(input('Введите число\n'))
try:
if x_var > 10:
raise MyException()
except MyException:
print(MyException())
# Вывод:

Введите число

11

Число слишком большое

Раз мы объявили метод __init__, следует сказать, что в него можно передавать аргументы:


class MyException(Exception):
def __init__(self, x):
self.x = x
self.message = 'Число {} слишком большое'.format(self.x)
super().__init__(self.message)

x_var = float(input('Введите число\n'))
if x_var > 10:
raise MyException(x_var)
# Вывод:

Введите число

11

Traceback (most recent call last):

File "C:/Users/ivand/PycharmProjects/pythonProject/main.py", line 9, in <module>

raise MyException(x_var)

__main__.MyException: Число 11.0 слишком большое

Запись в лог

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


import logging

logging.basicConfig(level=logging.DEBUG)
logging.debug(" Сообщения про отладку")
logging.info(" Информационные сообщения")
logging.warning(" Предупреждения")
logging.error(" Сообщения с ошибками")
logging.critical(" Ну очень важные сообщения")
# Вывод:

DEBUG:root: Сообщения про отладку

INFO:root: Информационные сообщения

WARNING:root: Предупреждения

ERROR:root: Сообщения с ошибками

CRITICAL:root: Ну очень важные сообщения

Параметр level= указывает, сообщения какого уровня заносить в лог. К примеру, если указать ‘level= logging.ERROR’, то логгироваться будут только сообщения уровня error и critical. Объединим логгирование и обработку исключений:


import logging

logging.basicConfig(filename="log.txt", level=logging.WARNING)
try:
print(10 / 0)
except Exception:
logging.error(str(Exception))

Содержимое файла log.txt:

ERROR:root:<class 'Exception'>

Иерархия исключений

В Python есть иерархия исключений. Это происходит из-за того, что их классы наследуются друг от друга. Вот полный список:

BaseException — базовое исключение, от которого берут начало все остальные

+SystemExit  — исключение, порождаемое функцией sys.exit при выходе из программы

+KeyboardInterrupt  — порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C)

+GeneratorExit  — порождается при вызове метода close объекта generator

+Exception – исключения

++StopIteration — порождается встроенной функцией next, если в итераторе больше нет элементов

++StopAsyncIteration используется для остановки асинхронного прохода

++ArithmeticError — арифметическая ошибка

+++FloatingPointError

+++OverflowError

+++ZeroDivisionError

++AssertionError— выражение в функции assert ложно

++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

+++ResourceWarning

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

Python developer handling user input errors.

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

age = int(input("Введите ваш возраст: "))
if age &gt;= 18: 
    print("Вы можете голосовать на выборах!")
else:
    print("Вы не можете голосовать на выборах.")

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

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

Чтобы избежать такой ситуации, можно использовать цикл while и обработку исключений. Вот как это можно сделать:

while True:
    try:
        age = int(input("Введите ваш возраст: "))
        if age &gt;= 18: 
            print("Вы можете голосовать на выборах!")
        else:
            print("Вы не можете голосовать на выборах.")
        break
    except ValueError:
        print("Извините, я не понял вас. Попробуйте снова.")

В этом случае, если пользователь введет некорректные данные, программа выдаст сообщение об ошибке и попросит ввести данные снова, а не завершится с ошибкой. Цикл while True будет повторяться до тех пор, пока пользователь не введет корректные данные и break не прервет его.

Таким образом, с помощью цикла while и обработки исключений можно обеспечить получение корректного ввода от пользователя в Python.

Понравилась статья? Поделить с друзьями:
  • Обработка ошибок ввода java
  • Обработка ошибок вба
  • Обработка ошибок баз данных delphi
  • Обработка ошибок vbs
  • Обработка ошибок vba access