Finally python что это
Перейти к содержимому

Finally python что это

  • автор:

Исключения в python. Конструкция try — except для обработки исключений

Python 3 логотип

Исключения (exceptions) — ещё один тип данных в python. Исключения необходимы для того, чтобы сообщать программисту об ошибках.

Самый простейший пример исключения — деление на ноль:

Разберём это сообщение подробнее: интерпретатор нам сообщает о том, что он поймал исключение и напечатал информацию (Traceback (most recent call last)).

Далее имя файла (File «»). Имя пустое, потому что мы находимся в интерактивном режиме, строка в файле (line 1);

Выражение, в котором произошла ошибка (100 / 0).

Название исключения (ZeroDivisionError) и краткое описание исключения (division by zero).

Разумеется, возможны и другие исключения:

В этих двух примерах генерируются исключения TypeError и ValueError соответственно. Подсказки дают нам полную информацию о том, где порождено исключение, и с чем оно связано.

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

  • BaseException — базовое исключение, от которого берут начало все остальные.
    • SystemExit — исключение, порождаемое функцией sys.exit при выходе из программы.
    • KeyboardInterrupt — порождается при прерывании программы пользователем (обычно сочетанием клавиш Ctrl+C).
    • GeneratorExit — порождается при вызове метода close объекта generator.
    • Exception — а вот тут уже заканчиваются полностью системные исключения (которые лучше не трогать) и начинаются обыкновенные, с которыми можно работать.
      • StopIteration — порождается встроенной функцией next, если в итераторе больше нет элементов.
      • ArithmeticError — арифметическая ошибка.
        • FloatingPointError — порождается при неудачном выполнении операции с плавающей запятой. На практике встречается нечасто.
        • OverflowError — возникает, когда результат арифметической операции слишком велик для представления. Не появляется при обычной работе с целыми числами (так как python поддерживает длинные числа), но может возникать в некоторых других случаях.
        • ZeroDivisionError — деление на ноль.
        • IndexError — индекс не входит в диапазон элементов.
        • KeyError — несуществующий ключ (в словаре, множестве или другом объекте).
        • UnboundLocalError — сделана ссылка на локальную переменную в функции, но переменная не определена ранее.
        • BlockingIOError
        • ChildProcessError — неудача при операции с дочерним процессом.
        • ConnectionError — базовый класс для исключений, связанных с подключениями.
          • BrokenPipeError
          • ConnectionAbortedError
          • ConnectionRefusedError
          • ConnectionResetError
          • IndentationError — неправильные отступы.
            • TabError — смешивание в отступах табуляции и пробелов.
            • UnicodeEncodeError — исключение, связанное с кодированием unicode.
            • UnicodeDecodeError — исключение, связанное с декодированием unicode.
            • UnicodeTranslateError — исключение, связанное с переводом unicode.

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

            Первый пример применения этой конструкции:

              
            
              
            

            Ещё две инструкции, относящиеся к нашей проблеме, это finally и else. Finally выполняет блок инструкций в любом случае, было ли исключение, или нет (применима, когда нужно непременно что-то сделать, к примеру, закрыть файл). Инструкция else выполняется в том случае, если исключения не было.

            Для вставки кода на Python в комментарий заключайте его в теги

            Обработка исключений Python — блок Try/Except, блок Finally

            В этом материале речь пойдет о блоках try/except , finally и raise . Вместе с тем будет рассмотрено, как создавать собственные исключения в Python.

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

            Рассмотрим разные типы исключений в Python, которые появляются при срабатывании исключения в коде Python.

            3. Блоки try/except

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

            try: for i in range(3): print(3/i) except: print("Деление на 0") print("Исключение было обработано") 

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

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

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

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

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

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

            a, b = 1, 0 try: print(a/b) print("Это не будет напечатано") print('10'+10) except TypeError: print("Вы сложили значения несовместимых типов") except ZeroDivisionError: print("Деление на 0") 

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

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

            a, b = 1, 0 try: print(a/b) except: print("Вы не можете разделить на 0") print("Будет ли это напечатано?") 
            Вы не можете разделить на 0 Будет ли это напечатано? 

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

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

            try: print('10'+10) print(1/0) except (TypeError,ZeroDivisionError): print("Неверный ввод") 
            Неверный ввод 

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

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

            try: print('1'+1) print(sum) print(1/0) except NameError: print("sum не существует") except ZeroDivisionError: print("Вы не можете разделить на 0") except: print("Что-то пошло не так. ") 
            Что-то пошло не так. 

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

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

            try: print("1") print("2") except: print("3") 

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

            Но может быть только один общий или блок по умолчанию типа except . Следующий код вызовет ошибку «default 'except:' must be last» :

            try: print(1/0) except: raise except: print("Исключение поймано") finally: print("Хорошо") print("Пока") 

            4. Блок finally в Python

            После последнего блока except можно добавить блок finally . Он исполняет инструкции при любых условиях.

            try: print(1/0) except ValueError: print("Это ошибка значения") finally: print("Это будет напечатано в любом случае.") 
            Это будет напечатано в любом случае. Traceback (most recent call last): File “”, line 2, in print(1/0) ZeroDivisionError: division by zero 

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

            А что будет, если исключение перехватывается в except ?

            try: print(1/0) except ZeroDivisionError: print(2/0) finally: print("Ничего не происходит") 
            Ничего не происходит Traceback (most recent call last): File "", line 2, in print(1/0) ZeroDivisionError: division by zero During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 4, in print(2/0) ZeroDivisionError: division by zero 

            Как видите, код в блоке finally исполняется в любом случае.

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

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

            raise ZeroDivisionError 
            Traceback (most recent call last): File "", line 1, in raise ZeroDivisionError ZeroDivisionError 

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

            a,b=int(input()),int(input()) # вводим 1 затем 0 if b==0: raise ZeroDivisionError 
            Traceback (most recent call last): File "", line 3, in raise ZeroDivisionError ZeroDivisionError 

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

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

            a,b=int(input()),int(input()) try: if b==0: raise ZeroDivisionError except: print("Деление на 0") print("Будет ли это напечатано?") 
            1 0 Деление на 0 Будет ли это напечатано? 

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

            raise KeyError 
            Traceback (most recent call last): File “”, line 1, in raise KeyError KeyError 

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

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

            try: print('1'+1) except: raise 
            Traceback (most recent call last): File “”, line 2, in print(‘1’+1) TypeError: must be str, not int 

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

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

            raise ValueError("Несоответствующее значение") 
            Traceback (most recent call last): File "", line 1, in raise ValueError("Несоответствующее значение") ValueError: Несоответствующее значение 

            6. assert в Python

            Утверждение (assert) — это санитарная проверка для вашего циничного, параноидального «Я». Оно принимает инструкцию в качестве аргумента и вызывает исключение Python, если возвращается значение False . В противном случае выполняет операцию No-operation (NOP).

            assert(True) # код работает дальше 

            Если бы инструкция была False ?

            assert(1==0) 
            Traceback (most recent call last): File “”, line 1, in assert(1==0) AssertionError 

            Возьмем другой пример:

            try: print(1) assert 2+2==4 print(2) assert 1+2==4 print(3) except: print("assert False.") raise finally: print("Хорошо") print("Пока") 
            1 2 assert False. Хорошо Traceback (most recent call last): File “”, line 5, in assert 1+2==4 AssertionError 

            Утверждения можно использовать для проверки валидности ввода и вывода в функции.

            a. Второй аргумент для assert

            Можно предоставить второй аргумент, чтобы дать дополнительную информацию о проблеме.

            assert False,"Это проблема" 
            Traceback (most recent call last): File “”, line 1, in assert False,”Это проблема” AssertionError: Это проблема 

            7. Объявление собственных исключений Python

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

            class MyError(Exception): print("Это проблема") raise MyError("ошибка MyError") 
            Traceback (most recent call last): File “”, line 1, in raise MyError(“ошибка MyError”) MyError: ошибка MyError 

            Вот и все, что касается обработки исключений в Python.

            8. Вывод: обработка исключений Python

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

            try except finally

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

            Данная составная инструкция производит обработку исключений для кода, идущего в блоке try.

            class MyException1(Exception): pass
            class MyChildException1(MyException1): pass

            class MyException2(Exception): pass
            class MyChildException2(MyException2): pass

            class MyException3(Exception): pass
            class MyChildException3(MyException3): pass


            def make_exception(exception_type):

            try:
            raise exception_type()

            except MyChildException1:
            print('MyChildException1')

            except (MyChildException2, MyException3):
            print('MyChildException2, MyException3')

            except:
            print('broad except')


            make_exception(MyChildException1) # MyChildException1
            make_exception(MyException2) # broad except
            make_exception(MyChildException3) # MyChildException2, MyException3
            Блок try
            • Если в ходе исполнения данного блока исключений не будет, то ни один из обработчиков не задействуется.
            • Если в ходе исполнения инструкций в этом блоке будет зафиксировано исключение, то начнётся поиск подходящего для него обработчика. Поиск производится по блокам except поочерёдно, поэтому более широкие типы исключений (базовые) имеет смысл ставить после более узких.
            Блок except

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

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

            • Если блок except используется без следующего за ним выражения, то он должен быть последним, потому что в нём производится обработка любых типов.
            • Если за блоком следует выражение, то оно будет выполнено. Если полученным в результате выполнения объект «совместим» с исключением, которые мы собираемся обработать, то будут выполнены инструкции, находящиеся в данном блоке. Объект считается совместимым с поднятым исключением, если является классом (непосредственным, либо базовым) исключения, либо кортежем, содержащим элемент, совместимый с исключением.
            • Если в ходе поиска обработчик найден не будет, то поиск будет продолжен среди обработчиков окружающего кода по стеку.

            На заметку

            Исключение распространяется по стеку вызова, если только на его пути не встретится блок finally, возбуждающий другое исключение. В этом случае прежнее исключением будет «потеряно» из-за нового.

            • Если в ходе выполнения выражения в блоке except будет случится исключение, то поиск обработчика прерывается. При этом начинается поиск нового обработчика в окружающем коде и по стеку вызова. При этом считается, что вся инструкция try except породила исключение.
            • Если найден подходящий блок except, то исключению назначается имя указанное после ключевого слова as (до +py.2.5 вместо ключевого слова использоваталсь запятая , ). После чего выполняется код в теле блока.

            На заметку

            Если вы хотите представить исключение в виде строки, то можете попробовать использовать формат %r вместо %s . Так результирующая строка будет содержать не только текст, переданный в инициализатор, но и название типа исключения.

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

            try: 
            raise Exception('arg1', 'arg2')

            except Exception as e:
            print(e)


            # >> ('arg1', 'arg2')

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

            На заметку

            До +py2.5 нельзя было использовать except совместно с finally, то есть, существовали две формы инструкции: try . except и try . finally .

            Блок else

            Инструкции в этом необязательном блоке выполняются по завершению блока try без исключений, а также без return , continue и break .

            def make_exception():

            try:
            return 'try'

            except:
            return 'except'

            else:
            return 'else'

            make_exception() # 'try'
            Блок finally

            В этом необязательно блоке можно определить код «уборки». Инструкции из этого блока будут выполнены после выполнения всех прочих блоков, в том числе если исключение не было обработано (в этом случае оно будет возбуждено повторно в конце блока finally автоматически) и если в блоке try присутствуют return или break . При этом информация об исключении недоступна.

            На заметку
            В существующих реализациях употребление continue в блоке finally не поддерживается.

            Если в блоке имеется инструкция return или break информация об исключении (если оно было) будет утеряна:

            def make_exception(): 
            try:
            1/0

            finally:
            return 'finally'

            make_exception() # 'finally'

            +py3.0 Если в блоке finally возбуждается новое исключение, то ему в качестве контекста будет назначено прежнее исключение. До -py3.0 в подобных сценариях информация об исключении терялась.

            На заметку
            Дополнительную информация об исключениях доступна в статье Встроенные исключения

            +py3.8 Теперь в блоке finally можно использовать инструкцию continue.

            Скорость выполнения

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

            До версии +py2.0 можно было часто видеть конструкцию следующего вида:

            try: 
            value = mydict[key]
            except KeyError:
            mydict[key] = getvalue(key)
            value = mydict[key]

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

            if key in mydict: 
            value = mydict[key]
            else:
            value = mydict[key] = getvalue(key)

            В данном конкретном примере можно было использовать value = dict.setdefault(key, getvalue(key)) , но только если вызов getvalue() достаточно дёшев (поскольку значение в любом случае будет вычислено).

            goto

            Использовать описанный ниже подход следует в случаях насущной необходимости, без фанатизма.

            При помощи инструкции можно соорудить достаточно функциональное подобие go и goto из других языков программирования.

            class label(Exception): pass # метка для goto

            try:
            .
            if condition: raise label() # переход к метке
            .
            except label: # реализация по метке
            pass
            .

            Этот подход не даст перейти внутрь цикла, но обычно подобное и не требуется, так как считается плохим применением goto .

            Блоки else-finally

            Что делать, если нужно закрыть файл (или выполнить любую clean-up операцию по освобождению ресурсов), вне зависимости, успешно отработал try блок или в нем возникло исключение.

            Нужно использовать блок finally

            • Если исключения не возникло, то после блока try выполняется блок finally.
            • Если исключение возникло и было перехвачено в одном из блоков except, то после него выполняется finally.
            • Если исключение возникло, но не нашлось в функции подходящего ecxept, то сначала будет выполнен блок finally, а потом исключение будет передано вверх по стеку вызова функций.

            finally scheme

            try: file = open('test.txt', 'rb') except IOError as e: print('Было вызвано исключение IOError. <>'.format(e.args[-1])) finally: print("Я буду напечатан вне зависимости от исключений в блоке try!") ​ # Вывод: Было вызвано исключение IOError. No such file or directory # Я буду напечатан вне зависимости от исключений в блоке try! 

            else - try и еще немного

            Если несколько выражений в try могут вызвать исключения и хочется отделить исключения одного от исключений другого, то можно или разбить его на несколько try-ecxept блоков, или (если исключения хочется обработать выше в стеке) написать else блок.

            try: do_some_stuff() except: # не указан тип? берем все исключения! rollback() raise # генерируем повтороно последнее исключение else: commit() 

            Все вместе

            try: print('Я уверен, исключений не будет!') except Exception: print('Исключение') else: # Любой код, который должен быть исполнен, если исключение в блоке # try не было вызвано, но для которого не должна проводиться # обработка исключений print('Я буду исполнен, если в try не будет исключений.' 'Мои исключения не будут обрабатываться.') finally: print('Я буду исполнен в любом случае!') ​ # Вывод: Я уверен, исключений не будет! # Я буду исполнен, если в try не будет исключений. Мои исключения не будут обрабатываться. # Я буду исполнен в любом случае! 

            try-ecxept-else-finally схема

            Перерисовать, ибо потащено с https://realpython.com/python-exceptions/#the-else-clause

            Контрольный выстрел

            Что вернет функция при следующих вызовах:

            def foo(a): b = [1, 2, 3] x = 5 / a y = b[a] print(x, a, y) def bzz(a): try: foo(a) print('try') return 1 # пока в try есть return, else не вызовется except: print('ecxept') return 2 else: print('else') return 3 finally: print('finally') return 4 return 5 print('bzz(<>)=<>'.format(2, bzz(2))) print('bzz(<>)=<>'.format(0, bzz(0))) print('bzz(<>)=<>'.format(7, bzz(7))) 

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

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