М. Лутц - Изучаем Python (4-е издание)- 2011 (1126907), страница 103
Текст из файла (страница 103)
Например, она принимает последовательности любого типа (в действительности – любые итерируемые объекты, включаяи файлы) и позволяет указывать более двух аргументов. При вызове с тремяаргументами, как показано в следующем примере, она конструирует списоккортежей, состоящих из трех элементов, выбирая элементы из каждой последовательности с одним и тем же смещением (с технической точки зрения, из Nаргументов функция zip создает N-мерный кортеж):>>> T1, T2, T3 = (1,2,3), (4,5,6), (7,8,9)>>> T3(7, 8, 9)>>> list(zip(T1,T2,T3))[(1, 4, 7), (2, 5, 8), (3, 6, 9)]Длина списка, возвращаемого функцией zip, равна длине кратчайшей из последовательностей, если аргументы имеют разную длину. В следующем примере выполняется объединение двух строк с целью параллельной обработкиих символов, при этом результат содержит столько кортежей, сколько былоэлементов в кратчайшей последовательности:>>> S1 = ‘abc’>>> S2 = ‘xyz123’>>>>>> list(zip(S1, S2))[(‘a’, ‘x’), (‘b’, ‘y’), (‘c’, ‘z’)]Эквивалентная функция map в Python 2.6В Python 2.X имеется родственная встроенная функция map, объединяющаяэлементы последовательностей похожим образом, но она не усекает результатпо длине кратчайшей последовательности, а дополняет недостающие элементызначениями None, если аргументы имеют разную длину:>>> S1 = ‘abc’>>> S2 = ‘xyz123’>>> map(None, S1, S2)# Только в 2.X[(‘a’, ‘x’), (‘b’, ‘y’), (‘c’, ‘z’), (None, ‘1’), (None, ‘2’), (None,’3’)]В этом примере используется вырожденная форма обращения к встроеннойфункции map, которая больше не поддерживается в Python 3.0.
Обычно онапринимает функцию и одну или более последовательностей и собирает результаты вызова функции с соответствующими элементами, извлеченными из последовательностей. Подробнее функция map будет рассматриваться в главах 19и 20. Ниже приводится короткий пример, где встроенная функция ord применяется к каждому символу в строке и собирает результаты в список (подобнофункции zip, в версии 3.0 map возвращает генератор, и поэтому, чтобы получитьПриемы программирования циклов413все ее результаты в интерактивном сеансе, обращение к ней следует заключитьв вызов функции list):>>> list(map(ord, ‘spam’))[115, 112, 97, 109]Тот же результат можно получить с помощью следующего цикла, но реализация на основе функции map зачастую выполняется быстрее:>>> res = []>>> for c in ‘spam’: res.append(ord(c))>>> res[115, 112, 97, 109]Примечание, касающееся различий между версиями: Вырожденная форма вызова функции map, когда в первом аргументевместо функции передается объект None, больше не поддерживается в Python 3.0, потому что в этом случае она в значительнойстепени совпадает с функцией zip (и, честно говоря, нескольконе соответствует основному назначению функции map).
В версии 3.0 вы можете либо использовать функцию zip, либо написать цикл, который сам дополняет недостающие результаты.Как это сделать, будет показано в главе 20, после того как мы познакомимся с дополнительными концепциями итераций.Конструирование словаря с помощью функции zipВ главе 8 я говорил, что функцию zip, используемую здесь, удобно применятьдля создания словарей, когда ключи и значения вычисляются во время выполнения программы. Теперь, когда мы поближе познакомились с этой функцией, я объясню, какое отношение она имеет к конструированию словарей. Каквы уже знаете, словарь всегда можно создать с помощью литерала словаря илиприсваивая значения ключам:>>> D1 = {‘spam’:1, ‘eggs’:3, ‘toast’:5}>>> D1{‘toast’: 5, ‘eggs’: 3, ‘spam’: 1}>>>>>>>>>>>>D1 = {}D1[‘spam’] = 1D1[‘eggs’] = 3D1[‘toast’] = 5Но как быть, если программа получает ключи и значения для словаря в видесписков во время выполнения, уже после того, как сценарий был написан? Например, предположим, что имеются следующие списки ключей и значений:>>> keys = [‘spam’, ‘eggs’, ‘toast’]>>> vals = [1, 3, 5]Один из способов превратить их в словарь состоит в том, чтобы передать спискифункции zip и затем выполнить обход полученного результата в цикле for:>>> list(zip(keys, vals))[(‘spam’, 1), (‘eggs’, 3), (‘toast’, 5)]414Глава 13.
Циклы while и for>>> D2 = {}>>> for (k, v) in zip(keys, vals): D2[k] = v...>>> D2{‘toast’: 5, ‘eggs’: 3, ‘spam’: 1}Однако, начиная с версии Python 2.2, можно обойтись без цикла for и простопередать результат вызова функции zip встроенному конструктору dict:>>> keys = [‘spam’, ‘eggs’, ‘toast’]>>> vals = [1, 3, 5]>>> D3 = dict(zip(keys, vals))>>> D3{‘toast’: 5, ‘eggs’: 3, ‘spam’: 1}Встроенное имя dict в языке Python в действительности является именемтипа (больше об именах типов и о создании подтипов вы узнаете в главе 31).Этот вызов производит преобразование списка в словарь, но в действительности это вызов конструктора объекта.
В следующей главе мы рассмотрим родственное, но более широкое понятие генераторов списков, которые позволяютсоздавать списки с помощью единственного выражения. Мы также вернемсяеще раз к генераторам словарей, появившихся в версии 3.0, которые являютсяальтернативой вызову dict для пар ключ/значение, объединенных в последовательность.Генерирование индексов и элементов: enumerateРанее мы рассматривали использование функции range для генерации индексов (смещений) элементов в строке вместо получения самих элементов с этимииндексами. Однако в некоторых программах необходимо получить и то, и другое: и элемент, и его индекс.
При традиционном подходе можно было бы использовать простой цикл for, в котором вести счетчик текущего индекса:>>> S = ‘spam’>>> offset = 0>>> for item in S:...print(item,...offset += 1...s appears at offsetp appears at offseta appears at offsetm appears at offset‘appears at offset’, offset)0123Этот способ вполне работоспособен, но в последних версиях языка Python те жесамые действия можно выполнить с помощью встроенной функции с именемenumerate:>>> S = ‘spam’>>> for (offset, item) in enumerate(S):...print(item, ‘appears at offset’, offset)...s appears at offset 0p appears at offset 1a appears at offset 2m appears at offset 3В заключение415Функция enumerate возвращает объект-генератор – разновидность объекта,который поддерживает протокол итераций, который мы будем рассматриватьв следующей главе, и более подробно будем обсуждать в следующей части книги.
В двух словах: он имеет метод __next__, вызываемый встроенной функциейnext и возвращающий кортеж (index, value) для каждого элемента списка. Мыможем использовать эти кортежи для присваивания в цикле for (точно так же,как и в случае с функцией zip):>>> E = enumerate(S)>>> E<enumerate object at 0x02765AA8>>>> next(E)(0, ‘s’)>>> next(E)(1, ‘p’)>>> next(E)(2, ‘a’)Обычно мы не видим всю эту механику, потому что во всех случаях (включаягенераторы списков – тема главы 14) протокол итераций выполняется автоматически:>>> [c * i for (i, c) in enumerate(S)][‘’, ‘p’, ‘aa’, ‘mmm’]Чтобы окончательно разобраться с такими понятиями итераций, как функцииenumerate, zip и генераторы списков, нам необходимо перейти к следующей главе, где производится разбор этих понятий с более формальной точки зрения.В заключениеВ этой главе мы исследовали инструкции циклов языка Python, а также некоторые концепции, имеющие отношение к циклам.
Мы рассмотрели инструкции циклов while и for во всех подробностях и узнали о связанных с нимиблоках else. Мы также изучили инструкции break и continue, которые могутиспользоваться только внутри циклов, и дополнительно познакомились с некоторыми встроенными инструментами, часто используемыми в цикле for,включая функции range, zip, map и enumerate (хотя понимание их роли, как итераторов в Python 3.0, не может быть полным до прочтения следующей главы).В следующей главе мы продолжим исследование механизмов итераций и рассмотрим генераторы списков и протокол итераций в языке Python�������������������������� – концепций, которые тесно связаны с циклами for. Там же будут объясняться некоторые тонкости применения итерируемых инструментов, с которыми мы встретились здесь, таких как функции range и zip.
Однако, как обычно, прежде чемдвинуться дальше, попробуйте ответить на контрольные вопросы.Закрепление пройденногоКонтрольные вопросы1. В чем заключаются основные различия между циклами while и for?2. В чем заключаются основные различия между инструкциями break и continue?416Глава 13. Циклы while и for3.
Когда выполняется блок else в циклах?4. Как в языке Python можно запрограммировать счетный цикл?5. Для чего может использоваться функция range в цикле for?Ответы1. Инструкция while обеспечивает способ организации универсальных циклов, а инструкция for предназначена для обхода элементов в последовательностях (в действительности – в итерируемых объектах). С помощью инструкции while можно сымитировать счетный цикл for, однако программный код получится менее компактным и может выполняться медленнее.2. Инструкция break осуществляет немедленный выход из цикла (управлениепередается первой инструкции, следующей за телом цикла while или for),а инструкция continue выполняет переход в начало цикла (в позицию непосредственно перед условным выражением в цикле while или перед извлечением очередного элемента в цикле for).3.
Блок else в циклах while или for выполняется один раз после выхода изцикла при условии, что цикл завершается обычным образом (без использования инструкции break). Инструкция break осуществляет немедленныйвыход из цикла и пропускает блок else (если таковая присутствует).4. Счетные циклы могут быть реализованы на базе инструкции while приусловии, что вычисление индексов будет производиться вручную, или набазе инструкции for, которая использует встроенную функцию range длягенерирования последовательности целых чисел. Ни один из этих способовне является предпочтительным в языке Python. Если вам необходимо просто обойти все элементы в последовательности, везде, где только возможно,используйте простой цикл for, без функции range или счетчиков. Такая реализация и выглядит проще, и обычно работает быстрее.5.
Встроенная функция range может использоваться в циклах for для организации фиксированного количества итераций, для реализации обхода смещений вместо самих элементов, для того, чтобы обеспечить пропуск элементов и чтобы получить возможность изменять список во время его обхода.Однако ни в одном из перечисленных случаев использование функции rangeне является обязательным условием, и для большинства из них имеютсяальтернативные способы – сканирование фактических элементов, использование операции извлечения среза с тремя пределами и генераторы списковзачастую являются более привлекательными решениями (несмотря на навязчивое стремление экс-C-программеров подсчитывать все подряд!).Глава 14.Итерации и генераторы, часть 1В предыдущей главе мы познакомились с двумя инструкциями циклов, имеющимися в языке Python, while и for.
Они могут использоваться при решениисамого широкого круга задач, где необходимо организовать многократное выполнение повторяющихся операций, однако необходимость перебора элементов последовательностей возникает настолько часто, что в язык Python быливведены дополнительные инструменты, делающие эту операцию более простойи эффективной. В данной главе мы начнем исследование этих инструментов.В частности, здесь будут рассматриваться родственные концепции протоколаитераций в языке Python������������������������������������������������������������������������������������������������������������ – модели, основанной на вызове методов, используемой в циклах for, а<b>Текст обрезан, так как является слишком большим</b>.