Саммерфилд - Программирование на Python 3 (1077331), страница 43
Текст из файла (страница 43)
Если это произойдет, интерпретатор сначала выполнит блок т с па11у, а затем передаст исключение вверх по стеку вызовов, при этом возвращаемое значение будет отброшено, так как функция завершится в результате необработанного исключения. А так как в данном примере нет соответствующего блока ехсерС, который обрабатывал бы ошибки, связанные с кодировкой, программа завершит свою работу с выводом диагностической информации. Предложение ехсерс в данном примере можно было бы записать более кратко: ехсерС ЕпчсгопеепСЕггог ае егг; ргспс[егг) геспгп [] Этот прием будет работать, так как Епнс гопаепСЕггог является базовым классом как для класса 10Еггог, так и для класса ОЯЕггог. В главе 8 демонстрируется более компактный способ, гаМенеажерв рантирующий закрытие файлов, не требующий наличия хеетехсте блока Сспа11у.
стр. 428 Возбуждение исключений Исключения представляют собой удобное средство управления потоком выполнения. Мы можем воспользоваться этим, используя либо встроенные исключения, либо создавая свои собственные и возбуждая нужные нам, когда это необходимо. Возбудить исключение можно одним из двух способов: 198 Глава 4. Управляющие структуры и функции га1ее ехсерттоп(агре) ге!ее В первом случае, то есть когда явно указывается возбуждаемое исключение, оно должно быть либо встроенным, либо нашим собственным, наследующим класс Ехсерт1оп. Коли исключению в виде аргумента передается некоторый текст, этот текст будет выведен на экран, если исключение не будет обработано программой. Во втором случае, то есть когда исключение не указывается, инструкция га1ве повторно возбудит текущее активное исключение, а в случае отсутствия активного исключения будет возбуждено исключение Ту реЕ г го г.
Собственные исключения Собственные исключения — это наши собственные типы данных (классы). Создание классов будет рассматриваться в главе 6, но поскольку создать простейший тип собственного исключения не составляет никакого труда, мы покажем, как это делается: с1еее ехоерттоплаве(оаееЕхоерттоп): реев Базовым классом ЬазЕхсерт! оп должен быть либо класс Ехсерт(оп, либо один из его наследников. Собственные исключения нередко используются, чтобы избежать глубоко вложенных циклов.
Например, допустим, что у нас имеется объект тзЬ1е, хранящий записи (строки), каждая из которых состоит из полей (столбцов), в каждом из которых может иметься несколько значений (элементов). Тогда поиск определенного значения можно было бы реализовать примерно так: трапа = Еа1ее Гаг гон, гесога 1п епавегате(таа)е): Гог са1авп, Г(е10 тп епавегате(гесога). Гаг тпаех, ттев тп епавегате((те!О): 1( 1(ев == тагдет: торпа = Тгае ЬгеаК 1( трапа: ЬгеаК тг торпа: Ьгеак тг гоапо: ргтпт(Гтоапо ат ((О), (1), (2))".(огват(гон, ао1авп, !поех)) е1ее. ргтпт("по! Гаапа") Эти 15 строк программного кода осложняет тот факт, что нам пришлось предусмотреть прерывание каждого цикла в отдельности.
Альтернативное решение заключается в использовании нестандартного исключения: Обработка исключений 199 с1авв ЕоопбЕхсертшп(Ехсертсоп): рава сгу: гог гов, гесогб сп епоаегасе(сао!е).' Гог со1оап, тсе1б сп еповегате(гесогб): тог спбех, !Сев ш епоаегате((се?б). 1Г стев == СагдеС: гасве еоопбехсерссоп() ехсерт ЕоопбЕхсертсоп ргспс( тропа ат ((0), (!), (2))".(огват(гов, со1оап, сабах)) е1ве: ргспт("пот тоопб") Этот прием позволил сократить программный код до десяти строк (или до 11, если включить определение класса исключения) и придал коду более удобочитаемый вид. Если искомый элемент будет найден, возбуждается наше собственное исключение и выполняется соответствующий блок ехсерс, при этом блок е1ве не выполняется. Если искомый элемент не будет найден, исключение не возбуждается и тогда в конце выполняется блок е1ве.
Рассмотрим еще один пример, демонстрирующий другие способы обработки исключений. Все фрагменты взяты из программы с«вес)ссауару, которая читает содержимое файлов НТМ?п имена которых передаются в виде аргументов командной строки, и выполняет некоторые простые проверки, чтобы убедиться, что все теги начинаются с символа «<» и заканчиваются символом «>» и все сущности оформлены правильно. В программе определяются четыре нестандартных исключения: с1авв 1пча11бепсссуеггог(Ехсерс1оп): рава с1авв 1пча1сбзоаеысепсссуеггог(спча1сбепсссуеггог): рава с1авв ?пча1сбп1роаЕпт!СуЕггог(!пна1сбЕпсссуЕггог): рава с1авв ?пна1сбтадсопсепсеггог(ехсерс!оп).
рава Второе и третье исключения наследуют первое; для чего это необходимо, мы увидим, когда будем обсуждать программный код, использующий эти исключение. Функция рагве(), использующая эти исключения, содержит более 70 строк программного кода, поэтому мы покажем только ту часть функции, которая имеет непосредственное отношение к обработке исключений. тп = лопе сгу: СП = орел(Г?1епаве, епсоб1пд="отса") еггогв = Еа1ве гог 1шо, 1спе ш еповегасе(гп, всагс=!): Гог со1овп, с сп епоаегасе( 1спе, всагт=с). сгу; Этот фрагмент начинается вполне традиционно, записывая значение )(опе в переменную, которая впоследствии будет ссылаться на объект гоо Глава 4.
Управляющие структуры и функции файла, и помещая все действия с файлом в блок 1гу. Программа читает содержимое файла строку за строкой и каждую строку символ за символом. Примечательно, что здесь имеется два блока 1гу — внешний используется для обработки исключений, которые могут возникнуть при работе с объектом файла, а внутренний — для обработки исключений, возникающих в ходе синтаксического анализа. е11( зтате == РАЯ31И0 ЕИТ1ТЧ; !!с==";": тт ест!ту.з!агтзн!тп("з"): !т тгозепзет(епт!ту( 1:]) - нех0161теи га1зе 1пча1тсвоаег1сЕпт1туЕггог() е1тг пот ел!!ту.
1за1рпа(): га1зе 1пча11сА1рпаепт!туеггог() Функция может находиться в нескольких состояниях, например, по- сле чтения символа амперсанда (й) она входит в состояние РАВ81И6 ЕИ- Т1ТУ и запоминает символы, расположенные между амперсандом и точ- кой с запятой (но не включая их), в строке ел!!Ту. о Часть программного кода, которая показана здесь, обраТип зет, „р !44' батывает случай, когда точка с запятой была обнаружена в процессе чтения сущности. Если это числовая сущность (начинается комбинацией символов «Ар», за которой следуют шестнадцатеричные цифры и символ «; », например: «ВИ20АС; »), мы преобразуем числовую часть в множество и исключаем из него все шестнадцатеричные цифры — если после этого множество окажется не- пустым, следовательно, в числе был указан как минимум один ошибочный символ, и мы возбуждаем собственное исключение.
Если это текстовая сущность (комбинация, начинающаяся с символа «6», за которым следуют алфавитные символы и символ «; », например: «((сору; »), мы возбуждаем исключение, если будет обнаружен неалфавитный символ. ехсерт (тпча11ОЕптттуЕггог, 1пча1тотарсоптептеггог) аз егг. тт !а!патассе(егг, 1пча1тоисаегтсепт1туеггог): еггог = "тпча1тс пиаегтс епт1ту" е1тг тз!патассе(егг, 1пча1ИА!рпаептыуеггог): еггог = "!пча11о а1рпаоеттс ептт!у" е1тг тз1пз!апсе(егг, !пча11отарсоптептеггог): еггог = "!пча!тс тар" ргтпт("ЕННОН (О) гп (!) оп 1!пе (2) со1оап (3)" 201 Обработка исключений ,тогват(аггог, гт1епаве, 1!по, оо1овп)) !Г ахтр оп Г!тат еггог: гатаа Если возникает исключение, связанное с синтаксическим анализом, оно будет перехвачено блоком ехсер!.
Используя базовый класс 1пыа1!СЕпт!туЕггог, мы перехватим оба типа исключений — 1пуа1!Ояовег!сЕпт!туЕггог и 1пыа1!ОА1рбаЕп!!туЕггог. После этого с помощью функции !а!па!алое() проверяется, какое именно исключение возникло, и определяется соответствующее сообщение об ошибке.
Встроенная функция !а!па!апре() возвращает Тгое, если первый ее аргумент имеет тот же тип, что и тип (или один из его базовых типов), переданный во втором аргументе. Можно было бы использовать отдельные блоки ехсер! для каждого из трех наших собственных исключений синтаксического анализа, но в данном случае, объединив обработку в одном блоке, нам удалось избежать необходимости повторять четыре последние строки (от инструкции ргтот() до инструкции гатае) в каждом из них. Программа имеет два режима работы. Если переменная НК(р оп Т! тат еггог имеет значение Га1ае, программа продолжит проверку файла даже после обнаружения синтаксической ошибки, что может привести к выводу множества сообщений об ошибках для каждого файла.
Если переменная ак!р оп Т!га! еггог имеет значение Тгое, то после выявления синтаксической ошибки (одной и только одной) в файле программа выведет сообщение об ошибке и повторно возбудит исключение синтаксического анализа, которое будет перехвачено внешним блоком т гу (где выполняется обработка каждого файла). а1!т агате == РАнз!ИО ент1ту; гатае ебееггог("в!аз!по ';' ат епо от " в т!1епаве) По завершении синтаксического анализа нам необходимо проверить, не оказались ли мы в середине сущности. Если это произошло, возбуждается встроенное исключение ЕОЕЕггог, сообщающее о встрече конца файла, которому мы передаем собственный текст сообщения.
Точно так же для этой цели мы могли бы использовать свое собственное исключение. ахоарт (тпыа1тОЕпт!туЕггог, 1пыа1!ОТадСоптептЕггог); раза а Уже было обработано ахоерт ЕОРЕггог аа агг: рг!пт("ЕННОН опахреотас ЕОЕ:", агг) ехоарт ЕпнтгопваптЕггог аа агг; ргтпт(егг) Глава 4. Управляющие структуры и функции Гтпа11у. тг гп 15 пот нппе.' тв.с1оее() Во внешнем блоке 1 гу мы использовали отдельные блоки ехсерс, потому что в каждом конкретном случае обработка выполняется по-разному. Если было получено исключение синтаксического анализа, мы знаем, что соответствующее сообщение уже было выведено и нам нужно лишь прервать работу с эти файлом и перейти к следующему, поэтому нам ничего не требуется делать в обработчике исключений.
Если было получено исключение ЕОГЕггог, это может быть результат действительно преждевременного достижения конца файла либо повторного его возбуждения. В любом случае мы выводим сообщение и текст исключения. Если возникло исключение Еп г1гопэептЕггсг (то есть если возникло исключение 10Еггсг или ОБЕггог), мы просто выводим сообщение исключения. В заключение, независимо от того, что произошло, если файл оказался открытым, мы закрываем его.
Собственные функции Функции представляют собой средство, дающее возможность упаковывать и параметризовать функциональность. В языке Ру1Ьоп можно создать четыре типа функций: глобальные функции, локальные функции, лямбда-функции и методы. Все функции, которые мы создавали до сих пор, являются глобальными функциями. Глобальные объекты (включая функции) доступны из любой точки программного кода в том же модуле (то есть в том же самом файле .ру), которому принадлежит объект.
Глобальные объекты доступны также и из других модулей, как будет показано в следующей главе. Локальные функции (их еще называют вложенными функциями)— это функции, которые объявляются внутри других функций. Эти функции видимы только внутри тех функций, где они были объявлены — они особенно удобны для создания небольших вспомогательных функций, которые нигде больше не используются. Мы познакомимся с ними в главе 7. Лямбда-функции — это выражения, поэтому они могут создаваться непосредственно в месте их использования; они имеют множество ограничений по сравнению с обычными функциями. Методы — это те же функции, которые ассоциированы с определенным типом данных и могут использоваться только в связке с этим типом данных; методы будут представлены в главе 6, когда будут рассматриваться вопросы объектно-ориентированного программирования. В языке Ру()топ имеется множество встроенных функций, а стандартная библиотека и библиотеки сторонних разработчиков добавляют 2оз Собственные функции еще сотни (тысячи, если посчитать еще и методы) поэтому большинство функций, которые нам могут потребоваться, уже написаны.