Лутц М. - Изучаем Python (1077325), страница 97
Текст из файла (страница 97)
функций, которые применяют другие функции к последовательностям. Родственные ей функции отфильтровывают элементы с помощью функций, выполняющих проверку (т!11ег), и применяют функции к парам элементов, накапливая результаты (гебзсе). Например, следующий вызов функции г!1(ег отбирает элементы последовательности больше нуля: »> гапев(-5, 5) [-5, -4, -3, -2, -1, О, 1, 2, 3, 4] »> Г!11ег((1ввЬбв х; х > 0), гвпзв(-5, 5)) [ 1, 2, 3, 4) Элементы последовательности, для которых применяемая функция возвращает истину, добавляются в список результатов.
Как и функция азр, 111тег является примерным эквивалентом цикла Гог, только она — встроенная функция и обладает высокой скоростью выполнения: »> гев=(1 »> Гсг х !и галсе(-5, 5): !Г х > 0; гез.аррепб(х) »> гвв [ 1, 2, 3, 4] гебзсе — более сложная функция. Ниже приводятся два вызова функции геб псе, которые вычисляют сумму и произведение элементов списка: »> гвбзсв((1авЬбв х, у; х + у), [1, 2, 3, 4)) 10 »> гебзсе((1авЬба х, у: х * у), [1, 2, 3, 4)) 24 452 Глава 17. Расширенные возможности функций На каждом шаге функция гебцсе передает текущую сумму или произведение вместе со следующим элементом списка 1заоба-функции.
По умолчанию первый элемент последовательности принимается в качестве начального значения. Ниже приводится цикл [ог, эквивалентный первому вызову, с жестко заданной операцией сложения внутри цикла: »> [ = [1 2 3 43 »> гев = 1[03 »> Гог х 1п [[1: 3: ГВВ = ГЕВ + Х »> гев 10 Написать свою версию функции гебосе (на тот случай, если она действительно будет убрана из РуЬЬоп 3.0) достаточно просто: »> бвГ вугебцсв(тцпс11оп, вероепсе): тв11у = вевцепсе[03 Гог пехт 1п вевоепсе[1:3'1 тв11у гопст1оп(1в11у, пехт) гетогп твиу »> вугебцсе((1ввобе х, у: х + у), [1 2, 3 4 53) 15 »> вугебосе((1ввЬбе х, у: х у), [1, 2, 3, 4, 53) 120 Если этот пример разжег ваш интерес, загляните также во встроенный модуль сре гаго г, который содержит функции, соответствующие встроенным выражениям, которые могут пригодиться при использовании некоторых функциональных инструментов: »> 1врогт орегетог »> гебосе(орегв1ог.вбб, [2, 4, 53) Ф Оператор словении в виде функции 12 »> гебссе((1ввЬбв х, у: х + у), [2, 4, 53) 12 Как и функция вар, Г111ег и гебосе поддерживают мощные приемы функционального программирования.
Некоторые программисты могут дополнить комплект средств функционального программирования языка РуСЬоп также 1ааэба-выражениями в комплексе с функцией арр1у и генераторами списков, которые рассматриваются в следующем разделе. Еще раз о генераторах списков: отображения Отображение операций на последовательности и сбор результатов являются настолько распространенной задачей в программировании на языке РуСЬоп, что в версии Ру[Ьоп 2.0 появилась новая особенность— генераторы списков, которые упрощают решение задач еще больше, чем только что рассмотренные функции. Мы уже встречались с гене- Еще раз о генераторах списков: отображения 453 раторами списков в главе 13,но, так как они относятся к средствам функционального программирования, таким как функции вар и 711- тег, здесь мы вернемся к этой теме еще раз.
С технической точки зрения эта особенность не привязана к функциям; как мы увидим, генераторы списков — более универсальные инструменты, чем пар и 111(ег, но иногда их проще понять, проводя аналогии с функциональными альтернативами. Основы генераторов списков Рассмотрим несколько примеров, демонстрирующих самые основы. Как было показано в главе 7, встроенная функция огб в языке РуаЬоп возвращает целочисленный код АЯСП единственного символа (обратной к ней является встроенная функция сяг — она возвращает символ, соответствующий коду АЯСП): >» огб( в ) 115 »> гев = [] >» Гог х 1п 'прае': гев.аррепб(огб(х)) »> гев [ 115, 112, 97, 109] Однако теперь, когда мы уже познакомились с функцией еар, тех же ре- зультатов мы можем достичь с помощью единственного вызова функ- ции без необходимости заботиться о создании и заполнении списка: »> гев = еар(огб, 'враа') »> гев [ 115, 112, 97, 109] Ф Прииенить функцию к последоеатепьности Но, начиная с версии Ру5Ьоп 2.0, те же результаты можно получить с помощью генератора списка: »> гев = [огб(х) гог х 1п 'прае'] Ф прииенит вирахение к последовательности »> гев [ 115, 112, 97, 109] Генераторы списков собирают результаты применения произвольного выражения к элементам последовательности и возвращают их в виде нового списка.
Синтаксически генераторы списков заключаются в квадратные скобки (чтобы показать, что они конструируют списки). В простейшем виде генератор списков представляет собой выражение, оперирующее переменной, за которым следует конструкция, напоминающая Теперь предположим, что нам необходимо получить коды АЯСП всех символов в строке.
Пожалуй, самый простой подход заключается в ис- пользовании цикла гог, в котором полученные результаты добавляют- ся в список; 454 Глава 17. Расширенные воэможности функций заголовок цикла Гог, в котором используется та же переменная. Во время выполнения интерпретатор РуФ)топ собирает результаты выражения для каждой итерации подразумеваемого списка. Предыдущий пример дает тот же результат, что цикл Гог и вызов функции вар выше.
Однако генераторы списков более удобны, особенно, когда требуется применить к последовательности произвольное выражение: »> [х ** 2 Гсг х 1п галде(10)1 [О, 1, 4. 9. 16, 25, 36, 49. 64. 81) Здесь создается список квадратов чисел от О до 9 (здесь мы позволили интерактивной оболочке автоматически вывести список — если вам необходимо сохранить список, присвойте его переменной). Чтобы выполнить аналогичные действия с помощью функции вар, потребовалось бы написать отдельную функцию, реализующую операцию возведения в квадрат. Так как эта функция нам не потребуется в другом месте программы, ее можно было бы (хотя это и не обязательно) реализовать не с помощью инструкции Ье(, а в виде 1авода-выраженияг »> аар((1ааЬЕа х: х " 2), галде(10)) [О, 1.
4, 9, 16, 25, 36, 49, 64. 81) Этот вызов выполняет ту же работу, и он всего на несколько символов длиннее эквивалентной реализации на базе генератора списка. Кроме того, он ненамного сложнее (по крайней мере, для тех, кто разбирается в 1азЬЬа-выражениях). Однако в случае более сложных выражений генераторы списков часто выглядят проще. В следующем разделе будет показано почему. Добавление проверок и вложенных циклов Генераторы списков обладают даже еще большей гибкостью, чем было показано до сих пор. Например, после цикла гог можно добавить оператор 11 для реализации логики выбора.
Генераторы списков с оператоРом 1( можно представить как аналог встроенной функции [11(е г, представленной в предыдущем разделе, — они пропускают элементы, для которых условное выражение в операторе 1( возвращает ложь. Ниже приводятся две версии реализации выбора четных чисел в диапазоне от 0 до 4 — с помощью генератора списка и с помощью функции Г!1(ег, которая использует небольшое 1аэоза-выражение для выполнения проверки. Для сравнения здесь также показана реализация на основе цикла (ог1 »> [х Гог х 1п галде(5) 11 х Х 2 = 01 [О, 2, 4) »> Г111ег((1аавса х; х Х 2 == О), галде(5)) [О, 2, 41 »> геа = [ ) »> Гсг х 1п галде(5): гще раз о генераторах списков: отображения [тхаг*-О: гев.аррепе(х) »> гев [0,2,4! Во всех этих версиях используется оператор деления по модулю (остаток от деления) %, с помощью которого определяются четные числа: если остаток от деления на два равен нулю, следовательно, число четное.
Вызов функции т[)тег здесь также выглядит ненамного длиннее, чем генератор списка. Однако, генераторы списков дают возможность объединять оператор ту и произвольные выражения, позволяя добиться эффекта действия функций т[! те г и вар в единственном выражении: »> [х .* 2 тог х 1п галде(10) (г х М 2 == О) [О, 4, 16. 36, 64] На этот раз создается список квадратов четных чисел в диапазоне от О до 9: цикл тот пропускает числа, для которых условное выражение, присоединенное справа, возвращает ложь, а выражение слева вычисляет квадраты, Эквивалентный вызов функции вар потребовал бы от нас больше работы — нам пришлось бы объединить выбор элементов с помощью функции [11(ег и обход списка с помощью вар, что в результате дает более сложное выражение; »> еар((1аеЬЕа х: х* 2), (11(ег((1аеаса х; х % 2 = 0), галде(10))) [О, 4, 16, 36, 64] В действительности, генераторы списков обладают еще большей гибкостью.
Они дают возможность запрограммировать любое число вложенных циклов то г, каждый из которых может сопровождаться собственным оператором тт с условным выражением. В общем виде генераторы списков выглядят следующим образом: [ ехргевв1оп гог тагдет1 тп аеоселсе1 [тт солш стол) гог гагдег2 1п аеоселсе2 [1г соло1ттол) ...
тот тагдетл тп аеооелсел' [11 солон стол] ] Вложенные операторы тот в генераторах списков действуют точно так же, как вложенные инструкции тот. Например, следующий фрагмент: »> гев = [х + у тог х 1п [О, 1, 2] тог у 1п [100, 200, 300]) »> гев [100, 200, 300, 101, 201, 301, 102, 202, 302] дает тот же результат, что и более объемный эквивалент: »> гев »> тог х 1п [О, 1, 2): тог у 1п [100, 200, 300]: гев.аррепс(х + у) »> гев [100.
200. 300, 101, 201, 301, 102, 202, 302] 456 Глава 17. Расширенные возможности функций Генераторы списков конструируют списки, однако итерации могут выполняться по любым последовательностям и итерируемым объектам. Следующий, немного похожий, фрагмент выполняет обход уже не списков чисел, а строк, и возвращает результаты конкатенации: »> [х + у Гог х 1п 'враз' Гог у 1п '8РАМ'] ['в8', 'вр', 'вА', 'вМ', 'р8', 'рР', 'РА', 'РМ', 'а8', 'аР', 'аА', 'аМ', 'е8', 'вР', 'вА', 'ММ'] В заключение приведу более сложный генератор списка, который иллюстрирует действие оператора 1(, присоединенного к вложенному оператору Гог: »> [(х, у) Гог х 1п гапце(5) 11 х Х 2 == О Гог у 1п гапце(5) 1Г у Х 2 == 1] [(О, 1), (О, 3), (2, 1), (2. 3), (4, 1), (4, 3)] Это выражение возвращает возможные комбинации четных и нечетных чисел в диапазоне от 0 до 4.