М. Лутц - Изучаем Python (4-е издание)- 2011 (1126907), страница 36
Текст из файла (страница 36)
Генераторы списков, применяемые к спискам, возвращают в качестве результатов новые списки, но могут использоваться и для любых другихобъектов, допускающих выполнение итераций. Например, ниже показано использование генератора списков для обхода жестко заданного в программномкоде списка координат и строк:>>> diag = [M[i][i] for i in [0, 1, 2]] # Выборка элементов диагонали матрицы>>> diag[1, 5, 9]>>> doubles = [c * 2 for c in ‘spam’] # Дублирование символов в строке>>> doubles[‘ss’, ‘pp’, ‘aa’, ‘mm’]Генераторы списков и родственные им встроенные функции map и filter – намой взгляд, достаточно сложная тема, чтобы говорить о них здесь более подробно.
Главная цель этого краткого обзора состоит в том, чтобы проиллюстрировать наличие как простых, так и очень сложных инструментов в арсеналеPython. Можно обойтись и без генераторов списков, но на практике они оказываются очень удобными и нередко обеспечивают более высокую производи-137Словарительность при работе со списками. Кроме того, их можно применять к любымтипам, являющимся последовательностями в языке Python, а также к некоторым типам, которые не являются последовательностями.
Мы еще будем говорить об этих выражениях далее в этой книге.Забегая вперед, отмечу, что в последних версиях Python����������������������������������������������можно также использовать конструкции генераторов списков, заключенные в круглые скобки, длясоздания генераторов, которые воспроизводят результаты по требованию. Например, ниже показано, как с помощью встроенной функции sum можно суммировать элементы в последовательности:>>> G = (sum(row) for row in M) # Генератор, возвращающий суммы элементов строк>>> next(G)6>>> next(G)# Вызов в соответствии с протоколом итераций15Того же эффекта можно добиться с помощью встроенной функции map, генерируя результаты за счет передачи элементов другой функции.
Обертываниевызова этой функции в список (в версии Python 3.0) вынуждает ее вернуть всезначения:>>> list(map(sum, M)) # Отобразить sum на элементы в M[6, 15, 24]В Python 3.0 синтаксис генераторов списков может также использоваться длясоздания множеств и словарей:>>> {sum(row) for row in M}# Создаст множество сумм строк{24, 6, 15}>>> {i : sum(M[i]) for i in range(3)} # Таблица пар ключ/значение сумм строк{0: 6, 1: 15, 2: 24}Фактически в версии 3.0 с помощью подобных выражений-генераторов можносоздавать списки, множества и словари:>>> [ord(x) for x in ‘spaam’]#[115, 112, 97, 97, 109]>>> {ord(x) for x in ‘spaam’}#{112, 97, 115, 109}>>> {x: ord(x) for x in ‘spaam’} #{‘a’: 97, ‘p’: 112, ‘s’: 115, ‘m’:Список кодов символовМножества ликвидируют дубликатыКлючи словарей являются уникальными109}Однако нам следует двигаться дальше, чтобы познакомиться с такими объектами, как генераторы, множества и словари.СловариСловари в языке Python – это нечто совсем иное (по выражению Монти Пайтона); они вообще не являются последовательностями, это то, что известно какотображения.
Отображения – это коллекции объектов, но доступ к ним осуществляется не по определенным смещениям от начала коллекции, а по ключам. В действительности отображения вообще не подразумевают какого-либоупорядочения элементов по их позиции, они просто отображают ключи на связанные с ними значения. Словари – единственный тип отображения в наборебазовых объектов Python – также относятся к классу изменяемых объектов:138Глава 4. Введение в типы объектов языка Pythonони могут изменяться непосредственно и в случае необходимости могут увеличиваться и уменьшаться в размерах подобно спискам.Операции над отображениямиКогда словарь определяется как литерал, программный код определения заключается в фигурные скобки и состоит из последовательности пар «ключ:значение».
Словари удобно использовать всегда, когда возникает необходимость связать значения с ключами, например чтобы описать свойства чеголибо. В качестве примера рассмотрим следующий словарь, состоящий изтрех элементов (с ключами «food» (продукт питания), «quantity» (количество)и «color» (цвет)):>>> D = {‘food’: ‘Spam’, ‘quantity’: 4, ‘color’: ‘pink’}Мы можем обращаться к элементам этого словаря по ключам и изменять значения, связанные с ключами. Для доступа к элементам словаря используетсятот же синтаксис, который используется для обращения к элементам последовательностей, только в квадратных скобках указывается не смещение относительно начала последовательности, а ключ:>>> D[‘food’]‘Spam’# Получить значение, связанное с ключом ‘food’>>> D[‘quantity’] += 1 # Прибавить 1 к значению ключа ‘quantity’>>> D{‘food’: ‘Spam’, ‘color’: ‘pink’, ‘quantity’: 5}Несмотря на то, что форма определения словаря в виде литерала, заключенного в фигурные скобки, достаточно наглядна, на практике чаще встречаютсядругие способы создания словарей.
Следующий пример начинается с созданияпустого словаря, который затем заполняется по одному ключу за раз. В отличие от списков, не допускающих присваивание значений отсутствующим элементам, присваивание значения по несуществующему ключу в словаре приводит к созданию этого ключа:>>>>>>>>>>>>D = {}D[‘name’] = ‘Bob’ # В результате присваивания создается ключD[‘job’] = ‘dev’D[‘age’] = 40>>> D{‘age’: 40, ‘job’: ‘dev’, ‘name’: ‘Bob’}>>> print(D[‘name’])BobВ этом примере ключи словаря играют роль имен полей в записи, которая описывает некоторого человека.
В других приложениях словари могут использоваться для замены операций поиска, поскольку обращение к элементу словаряпо ключу обычно выполняется быстрее, чем поиск, реализованный на языкеPython.Еще раз о вложенностиВ предыдущем примере словарь использовался для описания гипотетическойперсоны с помощью трех ключей. Теперь предположим, что информация име-139Словариет более сложную структуру. Возможно, придется записать имя и фамилию,а также несколько названий должностей, занимаемых одновременно. Этоприводит к необходимости использования вложенных объектов Python. Словарь в следующем примере определен в виде литерала и имеет более сложнуюструктуру:>>> rec = {‘name’: {‘first’: ‘Bob’, ‘last’: ‘Smith’},‘job’: [‘dev’, ‘mgr’],‘age’: 40.5}Здесь мы опять имеем словарь, содержащий три ключа верхнего уровня (ключи «name» (имя), «job» (должность) и «age» (возраст)), однако значения имеютболее сложную структуру: для описания имени человека используется вложенный словарь, чтобы обеспечить поддержку имен, состоящих из несколькихчастей, и для перечисления занимаемых должностей используется вложенныйсписок, что обеспечит возможность расширения в будущем.
К компонентамэтой структуры можно обращаться почти так же, как мы делали это в случаес матрицей, но на этот раз вместо числовых индексов мы используем ключисловаря:>>> rec[‘name’]# ‘Name’ – это вложенный словарь{‘last’: ‘Smith’, ‘first’: ‘Bob’}>>> rec[‘name’][‘last’] # Обращение к элементу вложенного словаря‘Smith’>>> rec[‘job’][‘dev’, ‘mgr’]# ‘Job’ – это вложенный список>>> rec[‘job’][-1]‘mgr’# Обращение к элементу вложенного списка>>> rec[‘job’].append(‘janitor’) # Расширение списка должностей Боба (Bob)>>> rec{‘age’: 40.5, ‘job’: [‘dev’, ‘mgr’, ‘janitor’], ‘name’: {‘last’: ‘Smith’,‘first’: ‘Bob’}}Обратите внимание, как последняя операция в этом примере выполняет расширение вложенного списка.
Так как список должностей – это отдельный отсловаря участок в памяти, он может увеличиваться и уменьшаться без какихлибо ограничений (размещение объектов в памяти будет обсуждаться в этойкниге позже).Основная цель демонстрации этого примера состоит в том, чтобы показать вамгибкость базовых типов данных в языке Python.
Здесь вы можете видеть, чтовозможность вложения позволяет легко воспроизводить достаточно сложныеструктуры данных. Для создания подобной структуры на языке C потребовалось бы приложить больше усилий и написать больше программного кода: нампришлось бы описать и объявить структуры и массивы, заполнить их значениями, связать их между собой и так далее. В языке Python все это делается автоматически – запуск выражения приводит к созданию всей структурывложенных объектов. Фактически это одно из основных преимуществ языковсценариев, таких как Python.Так же, как и в низкоуровневых языках программирования, мы могли бывыполнить освобождение памяти, занимаемой объектами, которые стали ненужны.
В языке Python память освобождается автоматически, когда теряет-140Глава 4. Введение в типы объектов языка Pythonся последняя ссылка на объект, например в случае присваивания переменнойкакого-либо другого значения:>>> rec = 0# Теперь память, занятая объектом, будет освобожденаС технической точки зрения, интерпретатор Python обладает такой особенностью, как сборка мусора, благодаря которой в ходе выполнения программыпроизводится освобождение неиспользуемой памяти, что избавляет нас отнеобходимости предусматривать специальные действия в программном коде.Интерпретатор освобождает память сразу же, как только будет ликвидирована последняя ссылка на объект.