Саммерфилд - Программирование на Python 3 (1077331), страница 93
Текст из файла (страница 93)
Здесь задействованы только самые основные средства — создается объект-регистратор, устанавливается уровень регистрации (поддерживается несколько уровней) и в качестве устройства вывода выбирается файл. о Функция-обертка начинает с того, что создает текст сословарей, общения, включив в него имя функции и значения аргустр.!60 ментов. После этого предпринимается попытка вызвать функцию и сохранить результат. Если возникло какое- либо исключение, оно сохраняется. В любом случае выполняется блок Г1па11у, и здесь в текст сообщения для регистрации добавляется результат (или исключение), после чего производится вывод сообщения в устройство регистрации. Если никаких исключений не возникло, результат возвращается вызывающей программе; в противном случае повторно возбуждается исключение, имитируя поведение оригинальной функции.
При работе в оптимизированном режиме переменная зеопд принимает значение Га1ве. В этом случае используется определение функции 1оддео(), которая просто возвращает указанную ей функцию, поэтому, кроме некоторой крошечной задержки, обусловленной созданием функции, во время выполнения никакого снижения производительности не наблюдается.
Обратите внимание, что в стандартной библиотеке присутствуют модули тгасе и ргот11е, которые могут запускать и анализировать ход выполнения программ и модулей, а также воспроизводить различные отчеты трассировки и профилирования, Оба они используют механизмы интроспекции, поэтому, в отличие от декоратора 61оддез, ни модуль тгасе, ни модуль ргог11е не требуют вносить изменения в исходные тексты. Аннотации функций Функции и методы могут определяться с помощью аннотаций — выражений, которые могут использоваться в сигнатурах функций, Ниже приводится общий синтаксис: Улучшенные приемы процедурного программирования 419 оет гипсыооуаие(рвгт: ехр1, раг2: ехр2, ..., рага: ехрм) -> гехр; яиые Каждое выражение, следующее за двоеточием (: ехрХ), является необязательным, как и выражение возвращаемого значения, следующее за стрелкой (-> гехр).
Последний (или единственный) позиционный параметр (если таковой имеется) может иметь форму *агдя, с аннотацией или без. Точно так же последний (или единственный) именованный параметр (если таковой имеется), может иметь форму **)пгагдв, и тоже с аннотацией или без. Если аннотации присутствуют в заголовке функции, они добавляются в словарь аппо(в11опв этой функции.
Если аннотации отсутствуют, словарь остается пустым. Ключами словаря служат имена параметров, а значениями — соответствующие им выражения. Синтаксис допускает возможность аннотировать все параметры, некоторые из них или ни одного и, кроме того, аннотировать или не аннотировать возвращаемое значение. Аннотации не имеют специального значения для интерпретатора. Единственное, что интерпретатор делает, когда встречает аннотации, — помещает их в словарь вппо1в11опв, оставляя за нами любые действия с ними. Ниже приводится пример аннотированной функции из модуля 0111; оет гя иптсоое риис(ваттов(в : втг) -> ьоо1: тог с 1п 5: тт иптсооеовтв.свтедогу(с)(0] != "Р": гетигп Ев1яе гетигп Тгие Каждый символ Юникода принадлежит какой-то конкретной категории, а каждая категория идентифицируется идентификатором из двух символов.
Все категории, имена которых начинаются с символа Р, содержат знаки пунктуации. В данном примере в качестве выражений аннотации мы использовали имена типов данных языка РУФйоп. Но они не имеют никакого значения для интерпретатора, что наглядно показывают следующие вызовы функции: Отт1.1я ип(соое рипстивт!оп(твеьгхв") в вернет; ев1яе 01>1.тя ип1соое росс(ив(топ(яычевт") Ф вернет тгие итт1. Тя июсаое рипстив(1оп(("' ", "Ф" ) ) в вернет; тгие В первом вызове используется позиционный аргумент, а во втором— именованный, просто для демонстрации, что оба варианта работают так, как и ожидается, В последнем вызове вместо строки передается кортеж, и это вполне допустимо, потому что интерпретатор никак не учитывает аннотации, кроме как записывает их в словарь вппо1а11- опв Если мы хотим извлечь толк из аннотаций, чтобы, например, выполнить проверку типов, можно предусмотреть декорирование требуемой 420 Глава 8.
Усовершенствованные приемы программирования функции соответствующим декоратором. Ниже приводится очень про- стой декоратор, выполняющий проверку типов: бе( этг1с11у 1уреб(типс11оп) . аппо1а1топэ = типс11оп, аппо1аттопа агц прес = тпэрест.цеттиыагдэрес(Гипс!топ) аэвег1 "гЕ(игп" тп аппо!а!!спи, "ч1эюпд 1уре Гог ге1игп уа1ие" Гог агд 1п агц врес.агдэ ч агд эрес.ячоп1уагдэ: аиэег1 агд тп аппота1!опе, ("э(выпц 1уре Гог рагапе1ег '" + агд + "'") етипс1оо1э чгарэ(гипс11оп) бе( чгаррег(*агдэ, **Хчагди): Гог паче, агд тп (1тэ1(гтр(агд прес.агдэ, агдз)) г 1твт(хчагдэ.ттечи())): аевег1 пипа!алое(агд, аппо1а11опэ[паее]), ( "ехрео1еб агдиееп1 '(9)' от (1) до1 (2)Г,ГОгеат( паче. аппо1а11опп[паче]. туре(аг9))) гепи11 = (ипо1топ(*агдэ, **Ичагдп) аэеегт тп1пптапсе(геэи11, аппо1аттопа["ге1игп"]), ( "ехрестеб ге!игл о( (О) до1 (1)".(огэат( аппо1а11опэ["ге1игп"], 1уре(геэи11))) ге1игп геэи11 ге1игп чгаррег Данный декоратор требует, чтобы все аргументы и возвращаемое значение были аннотированы соответствующими типами данных.
Он проверяет наличие в указанной функции аннотаций с типами для всех аргументов и возвращаемого значения и во время выполнения проверяет соответствие фактических аргументов ожидаемым типам данных. Модуль !пврес1 содержит мощные средства интроспекции для объектов. Здесь мы использовали лишь малую часть спецификаций аргументов, возвращаемых модулем, извлекая имена всех позиционных и именованных аргументов — в правильном порядке следования в случае позиционных аргументов. Затем эти имена и словарь с аннотациями используются для проверки наличия аннотации у каждого параметра и возвращаемого значения.
Функция-обертка, созданная внутри декоратора, сначала выполняет итерации по всем парам имя-аргумент для всех позиционных и именованных аргументов. Так как функция 21р() возвращает итератор, а метод б1с1. 11езв( ) возвращает представление словаря, мы не можем объединить их непосредственно, поэтому сначала каждый из них преобразуется в список. Если тип фактического аргумента отличается от типа, указанного в аннотации, инструкция авве г1 терпит неудачу; в противном случае вызывается фактическая функция, после чего выполняется проверка типа возвращаемого значения, и если это значение имеет требуемый тип, оно возвращается вызывающей программе.
В конце функция в1г!с11у 1уреб() как обычно возвращает функцию-обертку. Улучшенные приемы объектно-ориентированного программирования Обратите внимание, что проверка выполняется только в отладочном режиме (который является режимом выполнения по умолчанию и задается ключом командной строки -О или переменной окружения РУТНОИОРТТМ17Е). Если функцию тв сп)соле рспства11оп() декорировать декоратором овтгтс(1у турес и попытаться выполнить те же вызовы, что и прежде, но уже для декорированной версии, то аннотации вступят в силу, как показано ниже: тз вп1сосе рспп(ваттов(твеьг1а") а вернет: Ра1зе ж вп1сосе рвпстваттсп(вычэвт') в вернет: тгве гв вп1сосе рспп(ваттов(( ч ", "Ф")) в возбудит исключение лввегт1опеггсг Теперь проверка типов аргументов выполняется, поэтому в последнем случае возбуждается исключение дввегттопЕггаг, так как кортеж не является строкой или подклассом класса втг.
Теперь рассмотрим совершенно иное применение аннотаций. Ниже приводится маленькая функция„которая повторяет функциональность встроенной функции гапре(), за исключением того, что она всегда возвращает число с плавающей точкой. сег галсе ог (1сатв( агзв) -> "авшог=яе91па1с Реггтп": гетвгп ((1оат(х) гог х 1п галсе( агсв)) Сама функция никак не использует аннотацию, но совсем несложно создать инструмент, который будет импортировать все модули проекта и выводить список функций с именами авторов, извлекая имена функций из атрибута паве, а имена авторов — из элемента словаря аппотаттопв с ключом "гетвгп". Аннотации — это совершенно новая особенность языка Ру1)гоп, и языком не предусматривается какого-то предопределенного назначения для них, поэтому область применения аннотаций ограничивается только воображением программиста.