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

Возбуждение исключений.

Инструкция позволяет программисту принудительно вызвать указанное исключение. Например:

>>> raise NameError('HiThere')
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# NameError: HiThere

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

try
    raise NameError('HiThere')
except NameError
    print('An exception flew by!')
    raise

# An exception flew by!
# Traceback (most recent call last):
#   File "<stdin>", line 2, in <module>
# NameError: HiThere

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

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

Тип исключения — это класс экземпляра исключения, а значение — сам экземпляр.

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

raise Exception("foo occurred").with_traceback(tracebackobj)

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

try
    print(1  )
except Exception as exc
    raise RuntimeError("Something bad happened") from exc

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

# The above exception was the direct cause of the following exception:

# Traceback (most recent call last):
#   File "<stdin>", line 4, in <module>
# RuntimeError: Something bad happened

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

try
    print(1  )
except Exception as exc
    raise RuntimeError("Something bad happened")

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

# The above exception was the direct cause of the following exception:

# Traceback (most recent call last):
#   File "<stdin>", line 4, in <module>
# RuntimeError: Something bad happened

Цепочка исключений может быть явно подавлена ​​указанием в предложении :

Argument of an Exception

An exception can have an argument, which is a value that gives additional information about the problem. The contents of the argument vary by exception. You capture an exception’s argument by supplying a variable in the except clause as follows −

try:
   You do your operations here
   ......................
except ExceptionType as Argument:
   You can print value of Argument here...

If you write the code to handle a single exception, you can have a variable follow the name of the exception in the except statement. If you are trapping multiple exceptions, you can have a variable follow the tuple of the exception.

This variable receives the value of the exception mostly containing the cause of the exception. The variable can receive a single value or multiple values in the form of a tuple. This tuple usually contains the error string, the error number, and an error location.

Example

Following is an example for a single exception −

#!/usr/bin/python3

# Define a function here.
def temp_convert(var):
   try:
      return int(var)
   except ValueError as Argument:
      print ("The argument does not contain numbers\n", Argument)

# Call above function here.
temp_convert("xyz")

This produces the following result −

The argument does not contain numbers
invalid literal for int() with base 10: 'xyz'

Python Exception Handling Best Practices

  • Always try to handle the exception in the code to avoid abnormal termination of the program.
  • When creating a custom exception class, suffix its name with “Error”.
  • If the except clauses have the same code, try to catch multiple exceptions in a single except block.
  • Use finally block to close heavy resources and remove heavy objects.
  • Use else block to log successful execution of the code, send notifications, etc.
  • Avoid bare except clause as much as possible. If you don’t know about the exceptions, then only use it.
  • Create module-specific exception classes for specific scenarios.
  • You can catch exceptions in an except block and then raise another exception that is more meaningful.
  • Always raise exceptions with meaningful messages.
  • Avoid nested try-except blocks because it reduces the readability of the code.

5. Ключевое слово raise в Python

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

Разберемся на примере операции деления:

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

Что будет, если то же самое добавить в блоки try-except? Добавим следующее в код. Если запустить его, ввести 1 и 0, будет следующий вывод:

Рассмотрим еще несколько примеров, прежде чем двигаться дальше:

a. Raise без определенного исключения в Python

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

b. Raise с аргументом в Python

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

3. Блоки try/except

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

Программа вывела сообщение, потому что было обработано исключение.

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

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

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

a. Несколько except в Python

У одного блока может быть несколько блоков . Рассмотрим примеры с несколькими вариантами обработки.

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

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

Рассмотрим вывод:

b. Несколько исключений в одном except

Можно использовать один блок для обработки нескольких исключений. Для этого используются скобки. Без них интерпретатор вернет синтаксическую ошибку.

c. Общий except после всех блоков except

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

Здесь первая инструкция блока пытается осуществить операцию конкатенации строки python с числом. Это приводит к ошибке . Как только интерпретатор сталкивается с этой проблемой, он проверяет соответствующий блок , который ее обработает.

Отдельную инструкцию нельзя разместить между блоками и .

Это приведет к синтаксической ошибке.

Но может быть только один общий или блок по умолчанию типа . Следующий код вызовет ошибку :

The try-finally Clause

You can use a finally: block along with a try: block. The finally: block is a place to put any code that must execute, whether the try-block raised an exception or not. The syntax of the try-finally statement is this −

try:
   You do your operations here;
   ......................
   Due to any exception, this may be skipped.
finally:
   This would always be executed.
   ......................

Note − You can provide except clause(s), or a finally clause, but not both. You cannot use else clause as well along with a finally clause.

Example

#!/usr/bin/python3

try:
   fh = open("testfile", "w")
   fh.write("This is my test file for exception handling!!")
finally:
   print ("Error: can\'t find file or read data")
   fh.close()

If you do not have permission to open the file in writing mode, then this will produce the following result −

Error: can't find file or read data

Same example can be written more cleanly as follows −

#!/usr/bin/python3

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print ("Going to close the file")
      fh.close()
except IOError:
   print ("Error: can\'t find file or read data")

This produces the following result −

Going to close the file

When an exception is thrown in the try block, the execution immediately passes to the finally block. After all the statements in the finally block are executed, the exception is raised again and is handled in the except statements if present in the next higher layer of the try-except statement.

Что такое Traceback в Python?

Трассировка (Traceback) — это отчет, содержащий вызовы функций, сделанные в вашем коде в определенный момент. Трассировка известна под многими именами, включая stack trace (трассировку стека), stack traceback (трассировку стека), backtrace (обратную трассировку) и, возможно, другие. В Python используется термин traceback.

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

# example.py
def greet(someone):
    print('Hello, ' + someon)

greet('Chad')

Здесь вызывается функция greet() с параметром someone. Однако в greet() это имя переменной не используется. Вместо этого было ошибочно указано переменная someon в вызове print().

Примечание. В этом руководстве предполагается, что вы знаете что такое исключения в Python. Если вы незнакомы или просто хотите освежиться, то вам следует почитать Python Exceptions: Введение.

Когда вы запустите эту программу, вы получите следующий traceback:

$ python example.py
Traceback (most recent call last):
  File "/path/to/example.py", line 4, in <module>
    greet('Chad')
  File "/path/to/example.py", line 2, in greet
    print('Hello, ' + someon)
NameError: name 'someon' is not defined

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

В приведенной выше traceback исключением был NameError, что означает, что имеется ссылка на какое-то имя (переменная, функция, класс), которое не было определено. В нашем примере использовано имя — someon.

В последней строке в этом случае достаточно информации, чтобы помочь вам решить проблему. Поиск кода по имени someon, который является орфографической ошибкой, укажет вам правильное направление. Однако часто ваш код намного сложнее.

Конструкция Try .. Finally .. End

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

Синтаксис конструкции следующий:

Следует отметить, что, если исключение не будет возбуждено, то операторы из раздела Finally также будут освобождать ресурсы. Отличие заключается в том, что: • во-первых, при возникновении исключения часть операторов из раздела Try не выполняется, а при нормальной работе — выполняются все; • во-вторых, после освобождения ресурсов вследствие возбуждения исключения поиск обработчика исключения продолжится, поскольку исключения этой конструкцией не обрабатываются, а при нормальной работе будет выполняться оператор, следующий за конструкцией Try..Finally. Следует по возможности получать различные ресурсы перед конструкцией Try. Это гарантирует, что раздел Finally сможет должным образом освободить ресурсы.

Пример вложенных блоков try-except

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

x = 10
y = 0

try:
    print("outer try block")
    try:
        print("nested try block")
        print(x / y)
    except TypeError as te:
        print("nested except block")
        print(te)
except ZeroDivisionError as ze:
    print("outer except block")
    print(ze)

Вывод:

outer try block
nested try block
outer except block
division by zero

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

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

Посмотрите на следующий пример, который запрашивает у пользователя ввод до тех пор, пока он не введет допустимое целое число, но позволяет пользователю прервать программу (с помощью Control-C или того, что поддерживает конкретная операционная система); обратите внимание, что сгенерированное пользователем прерывание возникает как исключение KeyboardInterrupt (docs.python.org/3/library/exceptions.html#KeyboardInterrupt) (клавиатурное прерывание)

Оператор try (docs.python.org/3/reference/compound_stmts.html#try) работает следующим образом.

  • Сначала выполняется блок try (выражение(я) между ключевыми словами try (docs.python.org/3/reference/compound_stmts.html#try) и except (docs.python.org/3/reference/compound_stmts.html#except)).
  • Если исключение не произошло, блок except пропускается и выполнение оператора try закончено.
  • Если во время выполнения содержимого try возникает исключение, выражения ниже пропускаются. Затем, если тип возникшего исключения соответствует имени исключения после ключевого слова except, содержимое except выполняется, и затем выполнение продолжается после всего оператора try.
  • Если происходит исключение, которое не соответствует имени исключения в строке except, оно передается на внешний оператор try; если обработчик не найден, то исключение становится необработанным и выполнение останавливается с сообщением, как показано выше.

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

Класс в блоке except совместим с исключением, если он является таким же классом или базовым классом такового (но не наоборот — блок except, перечисляющий производный класс, несовместим с базовым классом). Например, следующий код выведет B, C, D:

Заметьте, что если бы блоки исключений шли в обратном порядке (первым ), то было бы выведено B, B, B, так как сработало бы первое сопоставление блока except.

В последнем пункте except можно опустить название исключения(ий), он будет служить «джокером»

Используйте эту возможность с особой осторожностью, так как таким образом легко замаскировать действительные ошибки программирования! Такой вариант также может быть использован для вывода сообщения об ошибке, и затем повторной генерации исключения (позволяет вызывающему также обработать исключение):. Оператор try ..

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

Оператор try … except имеет еще опциональную ветку else, которая если присутствует, должны следовать после всех веток except. Это полезно для кода, который должен быть выполнен, если в ветке try не возникло никакого исключения. Например:

Использование ветки else лучше, чем добавление дополнительного кода в try, потому что помогает избежать случайного перехвата исключения, которое не было сгенерировано кодом, находящимся под «защитой» оператора try … except.

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

В ветке except после имени исключения можно указать переменную. Переменная привязана к экземпляру исключения с аргументами хранящимися в . Для удобства экземпляр исключения определяет __str__() (docs.python.org/3/reference/datamodel.html#object.__str__), так что аргументы можно вывести сразу, без того, чтобы ссылаться на . Также возможно проиллюстрировать (instantiate) исключение прежде, чем сгенерировать его и добавлять какие-либо атрибуты, как пожелаете.

Если у исключения есть аргументы, они выводятся как последняя часть (‘detail’ — подробность) сообщения для необработанных исключений.

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

Catching Exceptions in Python

The try-except block can handle exceptions. This prevents abrupt exits of the program on error. In the example below we purposely raise an exception.

123456
try:     1 / except ZeroDivisionError:     print('Divided by zero')print('Should reach here')

After the except block, the program continues. Without a try-except block, the last line wouldn’t be reached as the program would crash.

In the above example we catch the specific exception ZeroDivisionError. You can handle any exception like this:

123456
try:     open("fantasy.txt")except:     print('Something went wrong')print('Should reach here')

You can write different logic for each type of exception that happens:

12345678910
try: except FileNotFoundError: except IsADirectoryError:except:print('Should reach here')

Related course: Complete Python Programming Course & Exercises

Traceback

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

Рассмотрим такой пример:

Traceback (most recent call last):
  File "/home/username/Develop/test/app.py", line 862, in _handle
    return route.call(**args)
  File "/home/username/Develop/test/app.py", line 1729, in wrapper
    rv = callback(*a, **ka)
  File "/home/username/Develop/test/__init__.py", line 76, in wrapper
    body = callback(*args, **kwargs)
  File "/home/username/Develop/test/my_app.py", line 16, in index
    raise Exception('test exception')

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

Рассмотрим какие еще встречаются комментарии к исключениям:

2 + '1'

Traceback (most recent call last):
  File "", line 1, in
    2 + '1'
TypeError unsupported operand type(s) for + 'int' and 'str'

В данном примере при попытке сложить целое число и строку мы получаем исключение TypeError. В описании сразу же становится ясно, что же мы не так написали.

int('qwerty')

Traceback (most recent call last):
  File "", line 1, in
    int('qwerty')
ValueError invalid literal for int() with base 10 'qwerty'

Приведение строчки к целому числу приводит к исключению ValueError.

В трэйсе этих двух примеров можно прочесть, что в таком-то файле на такой-то строчке есть ошибки.

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

8.6. User-defined Exceptions¶

Programs may name their own exceptions by creating a new exception class (see
for more about Python classes). Exceptions should typically
be derived from the class, either directly or indirectly.

Exception classes can be defined which do anything any other class can do, but
are usually kept simple, often only offering a number of attributes that allow
information about the error to be extracted by handlers for the exception. When
creating a module that can raise several distinct errors, a common practice is
to create a base class for exceptions defined by that module, and subclass that
to create specific exception classes for different error conditions:

class Error(Exception):
    """Base class for exceptions in this module."""
    pass

class InputError(Error):
    """Exception raised for errors in the input.

    Attributes:
        expression -- input expression in which the error occurred
        message -- explanation of the error
    """

    def __init__(self, expression, message):
        self.expression = expression
        self.message = message

class TransitionError(Error):
    """Raised when an operation attempts a state transition that's not
    allowed.

    Attributes:
        previous -- state at beginning of transition
        next -- attempted new state
        message -- explanation of why the specific transition is not allowed
    """

    def __init__(self, previous, next, message):
        self.previous = previous
        self.next = next
        self.message = message

Most exceptions are defined with names that end in “Error”, similar to the
naming of the standard exceptions.

Exceptions versus Syntax Errors

Syntax errors occur when the parser detects an incorrect statement. Observe the following example:

The arrow indicates where the parser ran into the syntax error. In this example, there was one bracket too many. Remove it and run your code again:

This time, you ran into an exception error. This type of error occurs whenever syntactically correct Python code results in an error. The last line of the message indicated what type of exception error you ran into.

Instead of showing the message , Python details what type of exception error was encountered. In this case, it was a . Python comes with various built-in exceptions as well as the possibility to create self-defined exceptions.

Дополнение: Полная форма try..except

Форма try…except не полная, полной же является try..except..else..finaly.

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

Иными словами, finally выполняет блок инструкций в любом случае, было ли исключение, или нет. А инструкция else выполняется в том случае, если исключения не было.

В целом, использование полной формы таково:

try
    исполяем какой-то код
except Exception as e
    обработка исключения
else
    код, который будет исполнен в случае, когда не возникает исключения
finally
    код, который гарантированно будет исполнен последним (всегда исполняется)

8.2. Exceptions¶

Even if a statement or expression is syntactically correct, it may cause an
error when an attempt is made to execute it. Errors detected during execution
are called exceptions and are not unconditionally fatal: you will soon learn
how to handle them in Python programs. Most exceptions are not handled by
programs, however, and result in error messages as shown here:

>>> 10 * (1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'int' object to str implicitly

The last line of the error message indicates what happened. Exceptions come in
different types, and the type is printed as part of the message: the types in
the example are , and .
The string printed as the exception type is the name of the built-in exception
that occurred. This is true for all built-in exceptions, but need not be true
for user-defined exceptions (although it is a useful convention). Standard
exception names are built-in identifiers (not reserved keywords).

The rest of the line provides detail based on the type of exception and what
caused it.

The preceding part of the error message shows the context where the exception
occurred, in the form of a stack traceback. In general it contains a stack
traceback listing source lines; however, it will not display lines read from
standard input.

User-Defined Exceptions

Python also allows you to create your own exceptions by deriving classes from the standard built-in exceptions.

Here is an example related to RuntimeError. Here, a class is created that is subclassed from RuntimeError. This is useful when you need to display more specific information when an exception is caught.

In the try block, the user-defined exception is raised and caught in the except block. The variable e is used to create an instance of the class Networkerror.

class Networkerror(RuntimeError):
   def __init__(self, arg):
      self.args = arg

So once you have defined the above class, you can raise the exception as follows −

try:
   raise Networkerror("Bad hostname")
except Networkerror,e:
   print e.args

Previous Page
Print Page

Next Page  

Ошибка рекурсии (RecursionError)

Эта ошибка связана со стеком и происходит при вызове функций. Как и предполагает название, ошибка рекурсии возникает, когда внутри друг друга исполняется много методов (один из которых — с бесконечной рекурсией), но это ограничено размером стека.

Все локальные переменные и методы размещаются в стеке. Для каждого вызова метода создается стековый кадр (фрейм), внутрь которого помещаются данные переменной или результат вызова метода. Когда исполнение метода завершается, его элемент удаляется.

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

Заключение

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

Получение вывода трассировки при запуске вашего кода — это отличная возможность улучшить ваш код.

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

Spread the love

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector