Саммерфилд - Программирование на Python 3 (1077331), страница 42
Текст из файла (страница 42)
Точно так же, когда возбуждается исключение, интерпретатор РуФ)топ пропускает предложение е1яе и пытается отыскать подходящий обработчик исключения (о чем будет рассказываться в следующем разделе) . Ниже приводится версия функции 1(ят Г1пс(), реализованная на базе цикла гог ... 1п, которая так же, как и версия на базе цикла иот1е„демонстрирует предложение е1ве в действии: Овт 1твт Гтпв(1вт, тагсат): гог тпоах, х вп апиаегате(1вт); 1Г х == тагаев: огеах е1вв: тповх = -1 гетигп тасях Как видно из этого фрагмента, переменные, созданные в выражении ехргеяятоп цикла Гог ... тп, продолжают существовать после завершения цикла. Как и любые локальные переменные, они прекращают свое существование после выхода из области видимости, включающей их. Обработка исключений Об ошибках и исключительных ситуациях интерпретатор Ру1)топ сообщает посредством возбуждения исключений, хотя в некоторых библиотеках сторонних разработчиков еще используются устаревшие приемы, такие как возврат»ошибочного» значения.
193 Обработка исключений Перехват и возбуждение исключений Перехватывать исключения можно с помощью блоков ггу ... ехсерг, которые имеют следующий синтаксис: ггу: ггу яшге ехсерт ехсергтпп дгсир1 ая уагтас1е1; ЕхСЕрт яютэ1 ехсерт ексергтоп дгсирр ая иагтаыер: ексерг яиггеэ е1яе: е1яе яигсе Ггпа11у; Ггпа11у яигте Эта конструкция должна содержать хотя бы один блок ехсерг, а блоки е1яе и Г!пэ11у являются необязательными. Блок е1яе яитте выполняется, только если блок ггу яитге завершается обычным способом, и не выполняется в случае возникновения исключения.
Если блок Г!пз11у присутствует, он выполняется всегда и в последнюю очередь. Каждая группа ехсерттрп дгоир в предложении ехсерт может быть единственным исключением или кортежем исключений в круглых скобках. Часть ая уэста(11е в каждой группе является необязательной. В случае ее использования в переменную уаг1а(11е записывается ссылка на исключение, которое возникло, благодаря этому к нему можно будет обратиться в блоке ехсерГ яи!те. Если исключение возникнет во время выполнения блока ггу яи1 ге, интерпретатор поочередно проверит каждое предложение ехсерг. Если будет найдена соответствующая группа ехсерттрп дгоир, будет выполнен соответствующий блок ехсерг яи! ге.
Соответствующей считается группа, в которой присутствует исключение того же типа, что и возникшее исключение, или возникшее исключение является подклассом' одного из исключений, перечисленных в группе. Например, если при поиске по словарю возникнет исключение КеуЕггог, первое предложение ехсерг, содержащее класс ехсерг!оп, будет считаться соответствующим, так как КеуЕггог является (косвенно) подклассом Ехсерг!оп.
Если ни одна из групп не содержит класс Ехсерг!ап (в чем нет ничего необычного), но имеется группа с классом (оокир- Как будет показано в главе 6, в объектно-ориентированном программировании обычно создаются иерархии классов, то есть один класс (тип данных) наследует другой класс. В языке Русаков родоначальником любой иерархии является класс оэ)ест — все остальные классы прямо или косвев.
но наследуют его. Подкласс — это класс, который наследует другой класс, поэтому эсе классы э языке РуФЬоп (эа исключением класса сь)эсг) являют. ся подклассами, так кэк эсэ они так или иначе наследуют класс сэтесг. Глава 4. Управляющие структуры и функции Рис. тт.1. Фрагмент иерархии классов исключений в языке Рутйоа Еггог, исключение КеуЕггог будет соответствовать этой группе, потому что класс КеуЕг гог является подклассом класса ЕоокорЕггог. И если нет группы, в которой присутствовал бы класс Ехсерт1оп или [соКорЕггог, но имеется группа, содержащая класс КеуЕггог, эта группа будет считаться соответствующей.
На рис. 4.1 приводится фрагмент иерархии классов исключений. Ниже приводится пример неправильного использования: тгу' х = 0[5] ехсерт [опхорЕггог; г НЕВЕРНЫЙ ПОРЯДОК ргшт["ЕосКор еггсг сссоггео") ехсерт КеуЕггсг. ргшт[ "1пхаыз Кеу озез") Если в словаре П не будет найден элемент с ключом б, для нас было бы желательно обработать исключение КеуЕггог, а не более общее ЕоаКорЕггог. Но в данном случае блок ехсерт с классом КеуЕггог никогда не будет выполняться.
В случае возникновения исключения КеуЕг гог соответствующим будет признан блок ехсерт с классом ЕООКорЕггог, потому что ЕПОКорЕггог является базовым классом для КеуЕггог, то есть класс ЕООКорЕггог находится выше класса КеуЕггог в иерархии классов исключений. Поэтому в случае использования нескольких блоков ехсерт необходимо всегда располагать их сверху вниз в порядке от более специализированных (расположенных ниже в иерархии) к более общим (расположенных выше в иерархии).
тгу. х = С[К Г'и) ехсерт ехсерттоп; г плОхАя пРАктикА ртпт["Зсаетптпр паррепев') Обработка исключений 195 Обратите внимание, что обычно не принято указывать класс Ехсеот 1 оп в предложении ехсерт, так как оно будет соответствовать любому исключению и легко может скрыть логические ошибки в программном коде. Возможно, в этом примере предполагалось перехватить исключение КеуЕггог, но если и имеет значение О, то мы неумышленно перехватим и исключение Еегор!х!з!опЕггог. Имеется также возможность записать предложение в форме ехсерт;, то есть вообще без указания группы исключений. Подобный блок ехсерт будет перехватывать любые исключения, включая те, что наследуют класс ВазеЕхсерт!оп„но не наследующие класс Ехсерт! оп (они не показаны на рис.
4. 1). Этот вариант порождает те же проблемы, что и при использовании предложения ехсерт Ехсерт!оп, и даже еще хуже; такое предложение никогда не должно использоваться. Если интерпретатор Ру1Ьоп не обнаружит ни одного соответствующего предложения ехсерт, он начнет подъем вверх по стеку вызовов, пытаясь отыскать подходящий обработчик исключения. Если такой обработчик не будет найден, программа завершит свою работу с выводом диагностической информации и сообщения об ошибке.
Если исключение не возникло, будет выполнен необязательный блок е1зе, если таковой имеется. И в любом случае, то есть независимо от того, возникло ли исключение или нет, и было ли оно обработано или интерпретатору предстоит выполнить подъем по стеку вызовов, всегда выполняется блок 1!па11у, если он присутствует. Если исключение не возникло или было обработано одним из блоков ехсерт, блок гтпа11у будет выполнен самым последним, но если для возникшего исключения не было найдено соответствующего блока ехсерт, то сначала будет выполнен блок г!па11у, и только потом интерпретатор передаст исключение вверх по стеку вызовов.
Такое гарантированное выполнение блока 1тпа11у может быть очень полезным, когда необходимо обеспечить корректное освобождение ресурсов. На рис. 4.2 демонстрируется порядок выполнения типичной конструкции тгу ... ехсерт ... 1!па11у. Ниже приводится окончательная версия функции 1!зт г!пс(), на этот раз она использует механизм обработки исключения: сег 1тзт гшс!)зт, !агре!): тгу тппех = 1зт.тпоех(тагдет) ехсерт Уа)пеЕггсг: тпсех = -т гетсгп тппех Здесь мы использовали конструкцию тгу ...
ехсерт для преобразования исключения в возвращаемое значение. Аналогичный подход можно использовать для перехвата одних исключений и возбуждения других — с этим приемом мы познакомимся очень скоро. Глава 4, Управляющие структуры и функции Обработанное исключение Необработанное искпючение Нормапьное ВыпапнВниВ -- сгу: .........и, № основние действия ехсерс ехсерсдол № обработка исключения .:::е.' Сдпа11у: ...м № освобождение ресурсов ....м № виполнение продолжается здесь м № исключение передается вверк ло стеку визовов Рис, 4.2.
Порядок выполнения конструкции сгу ... ексерс ... Ггюот!у Язык Рус)доп предоставляет возможность использовать более простую конструкцию Сгу ... Сдпа11у, которая в некоторых ситуациях может быть весьма удобна: сгу: сгу зидсе тдпа11у. Плапу зисе Неважно, что произойдет в блоке сгу зад се (кроме краха системы или программы!), в любом случае блок бала!!у аосте будет выполнен. Того же эффекта, аналогичного использованию конструкции Сгу... Сдпа11у, можно достичь с помощью инструкции кдтн и менеджера контекста (о которых будет рассказываться в главе 8).
Очень часто конструкция Сгу... ехсврт... Сдпа11у используется для обработки ошибок, возникающих при работе с файлами. Например, программа лоЫаи)тару принимает список имен файлов в виде аргументов командной строки и для каждого из них воспроизводит другой файл с тем же самым именем, но с расширением .пЬ, и с тем же содержимым, за исключением пустых строк. Ниже приводится функция геаб бата() из этой программы: ,.--- с ту: 'ч...........+ № оснавние действия т)ддддь ехсерс ексерсдоп: '----...м № обработка иоключения ,.'--~ гдпаыу: '.....„...„.~, № освобождение ресурсов 1.....ь № вилолнение продолжается здесь бег геаб сада(тд1епаюе); 1дпез = [) сп = папе сгу; га = преп(тд 1епаюе, епсобдпбы'отта") Сот 1дпе дп СП: дт 1дпе.зтгдс(): 1дпез.аррепбС!дпе) — с гу; 1...„...„,.ч.
№ основнне действия ехсерс ексерсдоп: № обработка исключения ;".:~ тдпа11у 1............+ № освобождение ресурсов 197 Обработка исключений ехсерт [1ОЕггаг, ОЯЕггог) аа егг: ргшс[егг) гесигп [1 Гспа11у: сг ГП са прс йопе: ГП. ссоее[) гесигп 1шее Изначально функция записывает в переменную гл значение [еопе, так как вполне возможно, что вызов функции среп [ ) потерпит неудачу, тогда переменной СЛ ничего не будет присвоено (и в ней останется значение Иопе) и будет возбуждено исключение.
Если возникнет одно из исключений, которые мы определили [10Еггог или ОЯЕггог), обработчик выведет сообщение об ошибке и вернет пустой список. Но, обратите внимание, что прежде, чем функция действительно вернет управление, будет выполнен блок т спа11у и файл будет закрыт, если перед этим он был благополучно открыт. Обратите также внимание, что если возникнет ошибка, связанная с кодировкой символов, файл все равно будет закрыт, хотя функция не предусматривает обработку соответствующего исключения (Уа1реЕггог).