Лутц М. - Изучаем Python (1077325), страница 95
Текст из файла (страница 95)
1авсбз-выражения создают локальную область видимости, как и вложенные инструкции бег, и автоматически получают доступ к именам в объемлющих функциях, в модуле и во встроенной области видимости (в соответствии с правилом ВКСВ): »> бес Кп19птв(): 111)е = '91г' ас11оп = (1ваЬба х; 1111е + ' ' + х) гетогп аст1оп В Заголовок в абъемлюаей беГ в Возвраеаег функцию »> аст = кп1дьсв() »> аст('говап') 'Втг гоств' В этом примере до версии РуФ)топ 2.2 значение для имени с т(1е переда- валось бы в виде значения по умолчанию — если вы забыли, почему, вернитесь к главе 16, где рассматривались области видимости.
Зачем использовать!атЫа-выражения? Вообще говоря, 1звсбз-выражения очень удобны для создания очень маленьких функций, к тому же они позволяют встраивать определения функций в программный код, который их использует. Они не являются предметом первой необходимости (вы всегда сможете вместо них использовать инструкции бег), но они позволяют упростить сценарии, где требуется внедрять небольшие фрагменты программного кода.
Например, позднее мы увидим, что функции обратного вызова часто реализуются в виде 1аззба-выражений, встроенных непосредственно в список аргументов, вместо инструкций бег где-то в другом месте в модуле и передаваемых по имени (примеры вы найдете во врезке «Придется держать в уме: функции обратного вызова» ниже в этой главе). 1авгоба-выражения также часто используются для создания таблиц переходов, которые представляют собой списки или словари действий, выполняемых по требованию. Например: 443 Анонимные функции: )агпЬба ( = [(1авоба х, х**2), (1ааЬба х: х"3), (1авЬба х: х* 4)1 гог т [п [: ргтпт Г(2) г Выведет 4, В, )б ртпг [[01(3) г Выведет 9 1авЬба-выражения наиболее полезны в качестве сокращенного варианта инструкции бег, когда необходимо вставить маленькие фрагменты исполняемого программного кода туда, где использование инструкций недопустимо. Например, этот фрагмент программного кода создает список из трех функций, встраивая 1авсба-выражения в литерал списка.
Инструкция бег не может быть вставлена в литерал, потому что это — инструкция, а не выражение. Подобные таблицы действий в языке РуС)юп можно создавать с помощью словаря и других структур данных: »> хеу = 'дог' »> ('а1геабу': (1авЬба; 2 + 2), 'дог': (1ааЬба: 2 ° 4), 'опе': (1ааЬба: 2 ° ° 6) ... )[хеу)() 6 В данном случае, когда интерпретатор РуФЬоп создает словарь, каждое из вложенных 1авЬба-выражений генерирует и оставляет после себя функцию для последующего использования — обращение по ключу извлекает одну из этих функций, а круглые скобки обеспечивают вызов извлеченной функции. При таком подходе словарь превращается в более универсальное средство множественного выбора„чем то, что я смог реализовать на основе инструкции [т в главе 12.
Чтобы реализовать то же самое без использования 1авЬба-выражений, пришлось бы написать три отдельные инструкции бег за пределами словаря, в котором эти функции используются: бет (1(): ге(огп 2 + 2 бет (2(); ге(огп 2 ° 4 бег г3(): гегогп 2 * ° 6 хеу = 'опе' ('а1геабу': т), 'дог'. (2, 'опе'; Г3)[кеу)() Этот прием тоже будет работать, но ведь инструкции бег могут располагаться в файле модуля достаточно далеко, несмотря на то, что они очень короткие. Близость программного кода, которую обеспечивают 1авЬба-выражения, особенно полезна, когда функции используются в единственном месте — если три функции в этом фрагменте не используются где-то еще, определенно имеет смысл встроить их в определение словаря в виде 1авЬба-выражений.
Кроме того, инструкции бег требуют даже для маленьких функций указывать имена, а они могут вступить в конфликт с другими именами в файле модуля. 444 Глава 17. Расширенные воэможности функций 1авЬСа-выражения также очень удобно использовать в списках аргументов функций — для определения временных функций, которые больше нигде в программе не используются, — мы увидим примеры такого использования ниже, в этой главе, когда будем изучать функцию вар. Как (не) запутать программный код на языке Ру~Ьоп Тот факт, что 1ввЬСа должно быть единственным выражением (а не серией инструкций), казалось бы, устанавливает серьезное ограничение на объем логики, которую можно упаковать в 1авЬСв-выражение, Однако если вы понимаете, что делаете, большую часть инструкций языка РуЬЬоп можно представить в форме выражений.
Например, представим, что необходимо вывести некоторую информацию из тела 1аввоа-выражения, тогда достаточно просто записать вув.вгвосг.нг1(е(в(г(х)+''1п') вместо рггпг х (в главе 11 объяснялось, что это именно то действие, которое выполняет инструкция рг1п1). Точно так же в 1ааЬСа-выражение можно заложить логику в виде трех- местного выражения 1Г/е1ве, представленного в главе 13, или использовать эквивалентную, хотя и более сложную комбинацию операторов зпв/ог, также описанную в главе 13.
Как говорилось ранее, следующую инструкцию: 1( а; Ь е1ве с можно имитировать одним из следующих примерно эквивалентных выражений: Ь 1( а е1зе с ((а апа Ь) ог с) Так как выражения, подобные этим, допустимо помещать внутрь 1авЬСа-выражения, они могут использоваться для реализации логики выбора внутри 1авЬСа-функций: »> 1еиег = (1ааЬСа х, у: х 1( х < у е1ве у) »> 1еиег('ЬЬ', 'аа') 'аа' »> 1саег('аа', 'ЬЬ') 'аа' Кроме того, если внутри 1авЬСа-выражения потребуется выполнять циклы, их можно заменить вызовами функции вар и генераторами списков (с ними мы уже познакомились в главе 13 и вернемся к ним еще раз ниже, в этой главе): »> 1апсы ауа »> вьсаа11 = (1авьса х: аар(аув.втссст.хг11е, х)) 445 Анонимные функции:!ашЬда »> з = зпопа1ц['зраа1п', '(оазз1п', 'еббз1п'1) зрвю (оаж о993 »> зпоха11 = 1ааьбв х: [вуз.ззбосз.иг1зе(11пе) гог 11пе зп х) »> С = зпоиа1Ц('Ьг19ПЬ1п', 'в1бе1п', 'о(1п', '11(е1п')) Ьг(си ыбе ог 1>(е Теперь, когда я продемонстрировал вам некоторые уловки, я должен просить вас использовать их только в случае крайней необходимости.
Без должной осторожности они могут сделать программный код нечитабельным (запутанным). Вообще, простое лучше сложного, явное лучше неявного, а понятные инструкции лучше таинственных выражений. С другой стороны, при умеренном использовании эти приемы могут быть полезны. Вложенные!атЫа-выражения и области видимости 1ашЬ<[а-выражения чаще других используют возможность поиска в области видимости вложенной функции (символ Е в названии правила [.ЕОВ, с которым мы познакомились в главе 1б).
Например, ниже 1ааббз-выражение находится внутри инструкции бе( — типичный случай — и потому получает значение имени х из области видимости объемлющей функции, имевшееся на момент ее вызова: »> бе( ас(1оп(х): гессгп (1ааЬба у'. х + у) Ф Создать и вернуть ф-цхю, запомнить х »> аст = ас11оп(99) »> зсз <гспс(1оп <1заьба> аг ОхООА16А66> »> асС(2) 101 В предыдущей главе, где обсуждались области видимости вложенных функций, не говорилось о том, что 1ааЬба-выражения обладают доступом к именам во всех объемлющих 1аасба-выражениях. Это сложно себе вообразить, но представьте, что мы записали предыдущую инструкцию бег в виде 1зесбз-выражения: »> астьоп = (1ааоба х: (1ааЬбв у: х + у)) »> асс = аст1оп(99) »> всз(3) 102 »> ((1авьба х: (1ааЬба у: х + у))(99)П4) 103 Глава 17.
Расширенные воэможности функций Придется держать в уме: функции обратного вызова Другое распространенное применение 1авббз-выражений состоит в определении функций обратного вызова для ТЫпФег СШ АР1. Например, следующий фрагмент создает кнопку, по нажатию которой на консоль выводится сообщение: !врет! еуз х = Впггоп( !ех! ='Ргесе ве', соввапб=(1авьба.зуз.э!брис.вг!!е('Враз'~п'))) Здесь в качестве обработчика события регистрируется функция, сгенерированная 1евЬбе-выражением в аргументе соввапб. Преимущество 1авЬба-выражения перед инструкцией бе( в данном случае состоит в том, что обработчик события нажатия на кнопку находится прямо здесь же, в вызове функции, создающей эту кнопку.
В действительности 1звбба-выражение откладывает исполнение обработчика до того момента, пока не произойдет событие: вызов метода нг!!е произойдет, когда кнопка будет нажата, а не когда она будет создана. Поскольку правила областей видимости вложенных функций применяются и к 1звсбе-выражениям, их проще использовать в качестве функций обратного вызова. Начиная с версии РуФ)!оп 2.2, они автоматически получают доступ к переменным объемлющих функций и в большинстве случаев не требуют передачи параметров со значениями по умолчанию. Это особенно удобно при обращении к специальному аргументу экземпляра зе11, который является локальной переменной в объемлющих методах классов (подробнее о классах рассказывается в шестой части книги): с1аее МуВн1: беГ вахентбре!е(ее1Г): Вп!гоп(соввапб=( 1авбба ее1(.бшр1ау("прав"))) беу б!ер1ау(ее1Г, веееаре); г.еспильепвать текс~ српбвеьеп.
В предыдущих версиях даже ее1т приходилось передавать в виде аргумента со значением по умолчанию. Эта структура 1авЬба-выражений создает функцию, которая при вызове создает другую функцию. В обоих случаях вложенное 1звсбз-выражение имеет доступ к переменной х в объемлющем 1звоба-выражении. Это фрагмент будет работать, но программный код выглядит весьма замысловато, поэтому в интересах соблюдения удобочитаемости лучше избегать использования вложенных друг в друга 1авЬба-выражений. 447 Применение функций к аргументам Применение функций к аргументам В некоторых программах бывает необходимо вызывать самые разные функции одинаковым образом, заранее не зная ни имен функций, ни их аргументов (примеры, где этот прием может быть полезен, будут показаны позднее).