понедельник, 7 декабря 2015 г.

Обработка исключений: try, except, else, finally

TraceBack: ошибки в Python



В процессе обучения, мы часто сталкиваемся с трекбеком, которым Python реагирует на возникающие ошибки. Это может быть не корректный ввод команды, неверное преобразование типов, обращение к несуществующему ключу или индексу, попытка совершить какое-то не предусмотренное действие с объектами, обратиться к несуществующей функции или методу, неправильно передать аргументы в функцию или метод... Python, встречая ошибку в синтаксисе или семантике кода, генерирует Traceback, в котором сообщает краткую информацию о том, в каком файле и в какой строке было возбуждено исключение(ошибка) и тип(название) данного исключения. Давайте посмотрим на некоторые исключения в Python:

>>> print var # Попытка вывести на экран, содержимое несуществующей переменной

Traceback (most recent call last):

  File "", line 1, in

NameError: name 'var' is not defined

>>>


Python вернул нам трекбек, с типом "NameError". Переменной с таким названием не существует. Любое обращение к несуществующей переменной, будет оканчиваться подобным исключением.

>>> a = 'Hello'

>>> b = 2

>>> a + b

Traceback (most recent call last):

  File "", line 1, in

TypeError: cannot concatenate 'str' and 'int' objects

>>>


Тут мы попытались сплюсовать 2 значения - строчное и численное, на что Python выдал нам исключение "TypeError" - ошибка с типами, Не возможно совершить конгатенацию с строчным(str) и  целочисленным(int) типами данных.

>>> int('hello') # Попытка приведения слова к числу

Traceback (most recent call last):

  File "", line 1, in

ValueError: invalid literal for int() with base 10: 'hello'

>>>


Тут мы попытались привести к целочисленному типу строку, которая содержит слово и Python вернул нам трекбек типа "ValueError" - ошибка содержимого, ошибочный литерал строки, который не может быть приведен к int() и должен содержать в себе число в десятичной(привычной нам) системе счисления.

>>> 5/0 # Попытка деления на 0

Traceback (most recent call last):

  File "", line 1, in

ZeroDivisionError: integer division or modulo by zero

>>>


Классическая ошибка в математике - попытка деления на 0, которая возбуждает исключение типа "ZeroDivisionError" - Невозможность делить на 0.

>>> 'test'.len()

Traceback (most recent call last):

  File "", line 1, in

AttributeError: 'str' object has no attribute 'len'

>>>


Тут мы попытались вызвать несуществующий метод в объекте строки, на что Python отреагировал трекбеком типа "AttributeError" - ошибка атрибута, такого атрибута(метода) в данном объекте не предусмотрено.

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

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


try except



После оператора try, мы пишем блок кода, который гипотетический может вызвать ошибку, а может и не гипотетически, Т.Е. Иногда мы будем сознательно создавать и обрабатывать некоторые исключения, Т.К. Это просто будет удобно. Оператор except может отлавливать ошибки двумя способами. Если мы укажем:

try:

    блок кода, где возникнет исключение

except:

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


В данной структуре, оператор except, отловит любую ошибку, которая может появиться в блоке кода после try. Но ведь в одном блоке кода может возникнуть несколько ошибок. Конечно, некоторые из ошибок мы можем физически разделить на несколько блоков при условии, что эти ошибки могут возникнуть в нескольких отдельных строках, а что делать, если одна строка может возбудить несколько исключений? Это достаточно легко представить. Кпримеру в одной строке может выполняться ошибочное преобразование типов, обращение к несуществующему ключу словаря, обращение к неверному индексу списка, вызов несуществующего метода какого-то объекта... Разве этого недостаточно? Естественно стоит утверждать, что таких ошибок программист должен избежать, но иногда их избежать просто невозможно, а иногда программист сам выстраивает такую логику, чтобы воспользовавшись исключениями, построить структуру своего кода. Чтобы нам отловить какой-то конкретный трекбек, после оператора except, нужно указать тип(название) исключения, кпримеру Type Error - ошибка преобразования типов. После try, мы можем указать необходимое количество except, каждй из которых будет отлавливать свою ошибку и выполнять соответствующий для них код. Давайте посмотрим на несколько примеров:

>>> try:

...     int('Hello') # Попытка преобразовать слово в число

... except:

...     print u"Ошибка преобразования типов!"

...

Ошибка преобразования типов!

>>>


Как видно, вместо трекбека, Python выполнил код после оператора except:

>>> d = {}

>>> d['one']

Traceback (most recent call last):

  File "", line 1, in

KeyError: 'one'

>>> try:

...     d['one']

... except KeyError:

...     print u"Ошибка, было обращение к несуществующему ключу в словаре"

...

Ошибка, было обращение к несуществующему ключу в словаре

>>>

>>> a = '10'

>>> b = '0'

>>> try:

...     int(a)/int(b)

... except ZeroDivisionError:

...     print u"Ошибка! Попытка деления на 0"

... except TypeError:

...     print U"Ошибка преобразования типов!"

...

Ошибка! Попытка деления на 0

>>>

>>> a = 'Hello'

>>> a

'Hello'

>>> b

'0'

>>> try:

...     int(a)/int(b)

... except ZeroDivisionError:

...     print u"Ошибка! Попытка деления на 0"

... except ValueError:

...     print U"Ошибка преобразования типов!"

...

Ошибка преобразования типов!

>>>


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


else



Да-да, в конструкции try except, тоже есть необязательная часть else. Если вспомнить все, что мы знаем о операторе else в конструкциях if else, while else, for else, мы можем предположить, что необязательная часть else, будет выполнена в том случае, если в блоке кода после try, исключение так и не будет возбуждено. Т.Е. Если в блоке кода после try, все пройдет гладко и Python в течении выполнения блока кода ниразу не попытается вернуть трекбек, после выполнения блока кода заложенного после try, будет выполнен блок кода после else. Конструкция следующая:

try:

    блок кода

except:

    блок кода

else:

    блок кода


Именно в таком порядке:

>>> try:

...     10/0

... except ZeroDivisionError:

...     print u"Попытка деления на 0"

... else:

...     print u"Ошибок небыло"

...

Попытка деления на 0

>>> try:

...     10/2

... except ZeroDivisionError:

...     print u"Попытка деления на 0"

... else:

...     print u"Ошибок небыло"

...

Ошибок небыло

>>>



finally



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

try:

    блок кода

except:

    блок кода

else: (Если таковой необходим в конструкции)

    блок кода

finally:

    блок кода


Зачем нам нужен отдельный блок кода, который будет выполнен при любых условиях? Пожалуй самым ярким примером будет случай, если нам нужно будет выполнить что-то в цикле for или while, при условии, что они будут обрываться оператором continue или break, а мы помним, что при использовании этих операторов, часть кода которая находится после них, выполнена не будет. Но если break или continue будут использованы в конструкции try except, которая будет иметь часть finally, код в блоке finally будет выполнен даже при условии прерывания цикла:

>>> a = 5

>>> b = 10

>>> while True:

...     try:

...             c = b / a

...             a = a -1

...     except:

...             print u"Ошибка!"

...             break

...     finally:

...             print u"Делим на ",a,u"результат ",c

...

Делим на  4 результат  2

Делим на  3 результат  2

Делим на  2 результат  3

Делим на  1 результат  5

Делим на  0 результат  10

Ошибка!

Делим на  0 результат  10

>>>


Как видим, блок кода после finally сообщал нам результат все время выполнения цикла и сообщил его даже тогда, когда была произведена попытка деления на 0 и цикл был прерван оператором break.

1 комментарий:

  1. ВСЕ ПРОЧИТАЙТЕ НАСТОЯЩЕЕ ОТЗЫВ О том, КАК Я ПОЛУЧИЛ СВОЙ КРЕДИТ ОТ КОМПАНИИ LEGIT И ДОВЕРЕННОЙ КРЕДИТНОЙ СРЕДИ Меня зовут Kjerstin Lis, я искал кредит для погашения своих долгов, все, кого я встречал, мошенничали и брали свои деньги, пока я наконец не встретил мистера Бенджамина Брейл Ли Он смог дать мне кредит в размере 450 000 рублей. Он также помог другим моим коллегам. Я говорю как самый счастливый человек во всем мире сегодня, и я сказал себе, что любой кредитор, который спасает мою семью от нашей бедной ситуации, я скажу имя всему миру, и я так счастлив сказать, что моя семья вернулся навсегда, потому что я нуждался в кредите, чтобы начать свою жизнь заново, потому что я одинокая мама с 3 детьми, и весь мир, казалось, висел на мне, пока я не имел в виду, что БОГ послал кредитора, который изменил мою жизнь и член моей семьи, БОЖИЙ кредитор, мистер Бенджамин, он был Спасителем БОГом, посланным для спасения моей семьи, и сначала я подумал, что это будет невозможно, пока я не получу кредит, я пригласил его к себе в семью -все вечеринка, от которой он не отказался, и я посоветую всем, кто действительно нуждается в кредите, связаться с г-ном Бенджамином Брейлом Ли по электронной почте (lfdsloans@outlook.com), потому что он самый понимающий и добрый кредитор. когда-либо встречал с заботливым сердцем. Он не знает, что я делаю это, распространяя свою добрую волю ко мне, но я чувствую, что должен поделиться этим со всеми вами, чтобы освободить себя от мошенников, пожалуйста, остерегайтесь подделок и свяжитесь с правильной кредитной компанией. com или whatsapp + 1-989-394-3740. ,

    ОтветитьУдалить