Лутц М. - Изучаем Python (1077325), страница 98
Текст из файла (страница 98)
Условные выражения отфильтровывают элементы в каждой из последовательностей. Ниже приводится эквивалентная реализация на базе инструкций: »> гев = [] »> рог х 1п гапце(5): 1тх12 О: Гог у 1п гапце(5): 1Г у Х 2 == 1; гев.аррепц((х, у)) »> гев [(О 1) (О 3), (2, 1), (2, 3), (4, 1), (4, 3)] Не забывайте, что в случае, когда генератор списков становится слишком сложным для понимания, вы всегда можете развернуть вложенные операторы Гог и 1Г (добавляя отступы), чтобы получить эквивалентные инструкции.
Программный код при этом получится более длинным, но более понятным. Эквивалентные реализации на основе функций вар и 11]те г оказались бы чрезвычайно сложными и имели бы глубокую вложенность вызовов, поэтому я даже не буду пытаться продемонстрировать их. Оставлю эту задачу в качестве упражнения мастерам Дзен, бывшим программистам на языке ЫЯР и просто безумцам.
Генераторы списков и матрицы Рассмотрим еще одно, более сложное применение генераторов списков, чтобы поупражнять мозги. Основной способ реализации матриц (они же — многомерные массивы) в языке Ру[]топ заключается в использовании вложенных списков. В следующем примере определяются матрицы ЗхЗ в виде вложенных списков: >» М = [[1, 2, 3], [4, 5, 6], 457 [ще раз о генераторах списков: отображения [7, 8, 9]] »>8=[[2, 2, 23, [3, Э, 3], [4,4,4П При такой организации всегда можно использовать обычную операцию индексирования для обращения к строкам и элементам внутри строк: »> М[1] [4, 5, 6] »> М[1П23 6 Генераторы списков являются мощным средством обработки таких структур данных, потому что они позволяют автоматически сканировать строки и столбцы матриц, Например, несмотря на то, что при такой структуре матрицы хранятся в виде списка строк, мы легко можем извлечь второй столбец, просто обходя строки матрицы и выбирая элементы из требуемого столбца или выполняя обход требуемых позиций в строках; >» [гон[1] гог гогг 1я м3 [2, 5,8] »> [я[гон][1] Гог готг 1о (О, 1, 2)] [2, 5, 83 Пользуясь позициями, мы также легко можем извлечь элементы, лежащие на диагонали.
В следующем примере используется функция гапде — она создает список смещений, который затем используется для индексирования строк и столбцов одним и тем же значением. В результате сначала выбирается М[0][0], затем М[1][1] и т. д. (здесь предполагается, что матрица имеет одинаковое число строк и столбцов): »> [й[1][1] тог 1 1п гаяде(1ео(й))] [1, 5, 9] Наконец, проявив немного изобретательности, генераторы списков можно использовать для объединения нескольких матриц. Первый пример ниже создает простой список, содержащий результаты умножения соответствующих элементов двух матриц, а второй создает структуру вложенных списков с теми же самыми значениями: »> [я[гон][со[] ° й[гое3[ооП тог гогг 1я гаяде(З) тог со[ [я гаяде(Э)3 [2.
4, 6. 12, 15, 18, 28, 32, Эб] »> [[М[гонИсо1] ° в[гон][со[] Гог оо1 1о гапде(З)] тог гон 1п гепде(З)] [[2. 4, б], [12, 15, 18]. [28. 82, Эб]3 В последнем выражении итерации по строкам выполняются во внешнем цикле: для каждой строки запускается итерация по столбцам, которая создает одну строку в матрице с результатами. Это выражение эквивалентно следующему фрагменту: Глава 17 Расширенные возможности функций »> гез »> Гог гоа !и гавре(3): !ар = [] тог со1 !п галде(3): !ар,аррепз(в[гон][со1] « в[гоп][со1]) газ.аррепс(!ар) »> гез [[2, 4, б], [12.
15, 18], [28. 32, 36]] В отличие от этого фрагмента, версия на базе генератора списков умещается в единственную строку, вероятно, работает значительно быстрее в случае больших матриц, но, правда, может и взорвать ваш мозг! На этом перейдем к следующему разделу. Понимание генераторов списков При такой степени гибкости генераторы списков очень быстро могут стать непостижимыми, особенно при наличии вложенных конструкций.
Поэтому начинающим осваивать язык РуС]зоп я рекомендую в большинстве случаев использовать простые циклы Гог и функцию азр (если они не становятся слишком сложными). Здесь также действует правило «чем проще, тем лучшее: лаконичность программного кода — намного менее важная цель, чем его удобочитаемость. Однако в настоящее время усложнение программного кода обеспечивает более высокую его производительность: проведенные тесты свидетельствуют, что функция азр работает практически в два раза быстрее, чем эквивалентные циклы Гог, а генераторы списков обычно немного быстрее, чем функция аар.' Это различие в скорости выполнения обусловлено тем фактом, что функция азр и генераторы списков реализованы на языке С, что обеспечивает более высокую скорость, чем выполнение циклов тог внутри виртуальной машины Ру(]топ (РУМ).
Применение циклов Гог делает логику программы более явной, поэтому я рекомендую использовать их для обеспечения большей простоты. Однако, функция азр и генераторы списков стоят того, чтобы знать и применять их для реализации простых итераций, а также в случаях, Производительность этих тестов может зависеть от вида решаемой задачи, а также от изменений и оптимизаций з самом интерпретаторе языка Ру!)топ. Например, в последиих версиях РуФоп была увеличена скорость выполнения инструкции цикла Гсг. «ем не менее, генераторы списков обычно показывают более высокую скорость работы, чем циклы тог, и даже более высокую, чем функция аар (хотя функция аар может выйти победителем в состязании среди встроенных функций). Чтобы проверить скорость рабо.
ты альтернативных реализаций, можно использовать функции т!ае. с1осК и т!ае т!ае в модуле тше. В версии Ру!)топ 2.4 появился новый модуль т!аетт, который рассматривается в разделе «Хронометраж итерационных альтернатив» далее в этой главе, Еще раз об итератора>с генераторы 459 когда скорость работы приложения имеет критически важное значение. Кроме того, функция вар и генераторы списков являются выражениями и синтаксически могут находиться там, где недопустимо использовать инструкцию тог, например в теле ]аазоз-выражений, в литералах списков и словарей и во многих других случаях, То есть вы должны стараться писать простые функции азр и генераторы списков, а в более сложных случаях использовать полные инструкции.
Еще раз об итераторах: генераторы В втой части книги мы уже познакомились с обычными функциями, которые получают входные параметры и возвращают результат. Однако точно так же возможно написать функцию, которая может возвращать значение, а позднее продолжить свою работу с того места, где она была приостановлена. Такие функции известны как генераторы, потому что они генерируют последовательность значений с течением времени.
Функции-генераторы во многом похожи на обычные функции, единственное отличие состоит в том, что они автоматически поддерживают итерационный протокол и могут использоваться в контексте итераций. Мы рассмотрели итераторы в главе 13, а здесь мы взглянем на них еще раз, чтобы увидеть, какое отношение они имеют к генераторам. Придется держать в уме: генераторы списков и п)ар Ниже приводится более реалистичный пример использования генераторов списков и функции вар (мы решали зту задачу с помощью генераторов списков в главе 13, а здесь мы снова вернемся к ней, чтобы продемонстрировать альтернативную реализацию на базе функции вар).
Вспомните, что метод файлов гезу]! пев возвращает строки с символом конца строки (т,п) в конце: »> ореп('вут11е'). геве!1пев() ['вввтп', 'ььь|п', 'ссс(п'] Если требуется удалить символы конца строки, их можно отсечь сразу во всех строках за одно действие с помощью генератора списков или функции вар: »> [11пе. гвтг1р() Гог !1пе 1п ореп('ву(1!е'). геве11пев()] ['ввв', 'ЬЬЬ', 'ссс'] »> [Ипе.гвтг1р() Гог 11пе 1п преп('еут11е')] ['вав'. 'ЬЬЬ', 'ссс'] »> ввр((1веосв 11пе; 11пе.гвтг1р()), ореп('ву(11е')) ['авв', 'ЬЬЬ', 'ссс'] 460 Глава 17. Расширенные возможности функций В последних двух случаях используются файловые ипзерапзорьс (по сути это означает, что вам не требуется вызывать метод, который будет читать строки из файла).
Вызов функции вар выглядит немного длиннее, чем генератор списков, но ни в одном из этих двух случаев не требуется явно управлять списком результатов. Кроме того, генераторы списков могут играть роль операции извлечения столбца. Стандартный прикладной интерфейс доступа к базам данных в языке РуЬ]топ возвращает результаты запроса в виде списка кортежей, как показано ниже. Список — это таблица, кортежи — это строки, а элементы кортежей — это значения столбцов: 1!атотсор1е = [('ьоь', 35, 'врг'), ('ве1', 40, 'оее')] Выбрать все значения из определенного столбца можно и вручную, с помощью цикла 10 г, но функция вар и генераторы списков сделают это быстрее и за один шаг: »> [аре тот (паве, аре, )оЬ) 1и 11атоттор1е] [35.
40] »> вар((1авЬаа (паве, аре, ]ЬЬ): аре), 11атоттор1е) [35. 40] В обоих случаях используется операция присваивания кортежа, чтобы извлечь значения в список. За дополнительной информацией о прикладных интерфейсах языка Рус]топ обращайтесь к другим книгам и источникам информации. В отличие от обычных функций, которые возвращают значение и завершают работу, функции-генераторы автоматически приостанавливают и возобновляют свое выполнение, при этом сохраняя информацию, необходимую для генерации значений.