Книга: Простой Python. Современный стиль программирования. 2-е изд.
Назад: Глава 7. Кортежи и списки
Дальше: Глава 9. Функции

Глава 8. Словари и множества

Если в словаре слово записано неправильно, как нам об этом узнать?

Стивен Райт

Словари

Словарь очень похож на список, но порядок элементов в нем не имеет значения и они не выбираются смещением, таким как 0 и 1. Вместо этого для каждого значения вы указываете связанный с ним уникальный ключ. Этот ключ чаще всего представляет собой строку, но, в принципе, может быть любым из неизменяемых типов: булевой переменной, целым числом, числом с плавающей точкой, кортежем, строкой, а также другими объектами, с которыми вы познакомитесь далее. Словари являются изменяемыми, а это значит, что вы можете добавить, удалить и изменить их элементы, имеющие вид «ключ — значение».

Если вы работали с другими языками программирования, которые поддерживают только массивы и списки, то полюбите словари.

109051.png

В других языках словари могут называться ассоциативнымимассивами, хешами или хеш-таблицей. В Python словарь также принято называть dict.

Создаем словарь с помощью {}

Чтобы создать словарь, нужно заключить в фигурные скобки ({}) разделенные запятыми пары ключ:значение. Самым простым словарем является пустой словарь, не содержащий ни ключей, ни значений:

>>> empty_dict = {}

>>> empty_dict

{}

Создадим небольшой словарь, включающий цитаты из «Словаря сатаны» Амброза Бирса:

>>> bierce = {

...     "day": "A period of twenty-four hours, mostly misspent",

...     "positive": "Mistaken at the top of one's voice",

...     "misfortune": "The kind of fortune that never misses",

...     }

>>>

Ввод имени словаря в интерактивный интерпретатор выведет все его ключи и значения:

>>> bierce

{'day': 'A period of twenty-four hours, mostly misspent',

'positive': "Mistaken at the top of one's voice",

'misfortune': 'The kind of fortune that never misses'}

109094.png

В Python допускается наличие запятой после последнего элемента списка, кортежа или словаря. Кроме того, не обязательно делать отступы, как делал я в предыдущем примере; когда вы вводите ключи и значения внутри фигурных скобок — это просто улучшает читабельность.

Создаем словарь с помощью функции dict()

Некоторым людям не нравится печатать так много фигурных скобок и кавычек. И вы можете создать словарь, передав именованные аргументы и значения в функцию dict().

Традиционный способ создания словаря:

>>> acme_customer = {'first': 'Wile', 'middle': 'E', 'last': 'Coyote'}

>>> acme_customer

{'first': 'Wile', 'middle': 'E', 'last': 'Coyote'}

С использованием dict():

>>> acme_customer = dict(first="Wile", middle="E", last="Coyote")

>>> acme_customer

{'first': 'Wile', 'middle': 'E', 'last': 'Coyote'}

Одним из ограничений второго способа является то, что имена аргументов должны представлять собой корректные имена переменных (в них не должны использоваться пробелы и ключевые слова):

>>> x = dict(name="Elmer", def="hunter")

  File "<stdin>", line 1

    x = dict(name="Elmer", def="hunter")

                             ^

SyntaxError: invalid syntax

Преобразуем с помощью функции dict()

С помощью функции dict() можно преобразовывать двузначные последовательности в словари. (Иногда вы можете столкнуться с такими последовательностями «ключ — значение», как «Стронций, 90, углерод, 14».) Первый элемент каждой последовательности применяется как ключ, второй — как значение.

Для начала рассмотрим небольшой пример использования lol — списка, состоящего из двузначных списков:

>>> lol = [ ['a', 'b'], ['c', 'd'], ['e', 'f'] ]

>>> dict(lol)

{'c': 'd', 'a': 'b', 'e': 'f'}

Мы могли бы использовать любую последовательность, содержащую последовательности из двух элементов. Рассмотрим другие примеры.

Список, содержащий двухэлементные кортежи:

>>> lot = [ ('a', 'b'), ('c', 'd'), ('e', 'f') ]

>>> dict(lot)

{'c': 'd', 'a': 'b', 'e': 'f'}

Кортеж, включающий двухэлементные списки:

>>> tol = (['a', 'b'], ['c', 'd'], ['e', 'f'])

>>> dict(tol)

{'c': 'd', 'a': 'b', 'e': 'f'}

Список, содержащий двухсимвольные строки:

>>> los = [ 'ab', 'cd', 'ef' ]

>>> dict(los)

{'c': 'd', 'a': 'b', 'e': 'f'}

Кортеж, содержащий двухсимвольные строки:

>>> tos = ('ab', 'cd', 'ef')

>>> dict(tos)

{'c': 'd', 'a': 'b', 'e': 'f'}

В подразделе «Итерируем по нескольким последовательностям с помощью функции zip()» главы 7 вы уже познакомились с функцией zip(), которая позволит вам легко создавать такие двухэлементные последовательности.

Добавляем или изменяем элемент с помощью конструкции [ключ]

Добавить элемент в словарь довольно легко. Просто обратитесь к элементу по его ключу и присвойте ему значение. Если ключ уже существует в словаре, имеющееся значение будет заменено новым. Если ключ новый, он и указанное значение будут добавлены в словарь. В отличие от списков, здесь вам не нужно беспокоиться о том, что Python сгенерирует исключение во время присваивания нового элемента, если вы укажете индекс, который выходит за пределы существующего диапазона.

Сейчас мы создадим словарь с перечислением участников комик-группы из Великобритании Monty Python, используя их фамилии в качестве ключей, а имена — в качестве значений:

>>> pythons = {

...     'Chapman': 'Graham',

...     'Cleese': 'John',

...     'Idle': 'Eric',

...     'Jones': 'Terry',

...     'Palin': 'Michael',

...     }

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Idle': 'Eric',

'Jones': 'Terry', 'Palin': 'Michael'}

Не хватает одного участника — уроженца Америки Терри Гиллиама. Здесь вы увидите попытку неизвестного программиста его добавить. Однако программист ошибся, когда вводил имя:

>>> pythons['Gilliam'] = 'Gerry'

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Idle': 'Eric',

'Jones': 'Terry', 'Palin': 'Michael', 'Gilliam': 'Gerry'}

А вот код другого программиста, который исправил эту ошибку:

>>> pythons['Gilliam'] = 'Terry'

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Idle': 'Eric',

'Jones': 'Terry', 'Palin': 'Michael', 'Gilliam': 'Terry'}

Используя один и тот же ключ ('Gilliam'), мы заменили исходное значение 'Gerry' на 'Terry'.

Помните, что ключи в словаре должны быть уникальными. Именно поэтому мы в качестве ключей использовали фамилии, а не имена — двух участников Monty Python зовут Терри. Если вы примените ключ более одного раза, победит последнее значение:

>>> some_pythons = {

...     'Graham': 'Chapman',

...     'John': 'Cleese',

...     'Eric': 'Idle',

...     'Terry': 'Gilliam',

...     'Michael': 'Palin',

...     'Terry': 'Jones',

...     }

>>> some_pythons

{'Graham': 'Chapman', 'John': 'Cleese', 'Eric': 'Idle',

'Terry': 'Jones', 'Michael': 'Palin'}

Сначала мы присвоили значение 'Gilliam' ключу 'Terry', а затем заменили его на 'Jones'.

Получаем элемент словаря с помощью конструкции [ключ] или функции get()

Этот вариант использования словаря — самый распространенный. Вы указываете словарь и ключ, чтобы получить соответствующее значение. Применим some_phyton из предыдущего подраздела:

>>> some_pythons['John']

'Cleese'

Если ключа в словаре нет, будет сгенерировано исключение:

>>> some_pythons['Groucho']

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

KeyError: 'Groucho'

Есть два хороших способа избежать возникновения подобного исключения. Первый — с помощью ключевого слова in проверить, имеется ли заданный ключ. Этот способ вы уже видели в предыдущем подразделе:

>>> 'Groucho' in pythons

False

Второй способ — использовать специальную функцию словаря get(). Вы указываете словарь, ключ и опциональное значение. Если ключ существует, вы получите связанное с ним значение:

>>> pythons.get('John')

'Cleese'

Если такого ключа нет, вы получите опциональное значение:

>>> pythons.get('Groucho', 'Not a Python')

'Not a Python'

В противном случае вам будет возвращен объект None (интерактивный интерпретатор ничего не выведет):

>>> pythons.get(Groucho')

>>>

Получаем все ключи с помощью функции keys()

Вы можете использовать функцию keys(), чтобы получить все ключи словаря. Для следующих примеров обратимся к другому словарю:

>>> signals = {'green': 'go', 'yellow': 'go faster', 'red': 'smile for the camera'}

>>> signals.keys()

dict_keys(['green', 'red', 'yellow'])

109100.png

В Python 2 функция keys() возвращает простой список. В Python 3 эта функция возвращает dict_keys() — итерабельное представление ключей. Это удобно для крупных словарей, поскольку не требует времени и памяти для создания и сохранения списка, которым вы, возможно, даже не воспользуетесь. Но зачастую вам требуется именно список. В Python 3 надо вызвать функцию list(), чтобы преобразовать dict_keys в список.

>>> list(signals.keys())

['green', 'red', 'yellow']

В Python 3 вам также необходимо применять функцию list(), чтобы преобразовывать результат работы функций values() и items() в обычные списки. Я пользуюсь этой функцией в своих примерах.

Получаем все значения с помощью функции values()

Чтобы получить все значения словаря, используйте функцию values():

>>> list(signals.values())

['go', 'smile for the camera', 'go faster']

Получаем все пары «ключ — значение» с помощью функции items()

Когда вам нужно получить все пары «ключ — значение» из словаря, используйте функцию items():

>>> list(signals.items())

[('green', 'go'), ('red', 'smile for the camera'), ('yellow', 'go faster')]

Каждая пара будет возвращена в виде кортежа, например ('green','go').

Получаем длину словаря с помощью функции len()

Количество пар «ключ — значение» определяется так:

>>> len(signals)

3

Объединяем словари с помощью конструкции {**a, **b}

В версиях Python 3.5 и выше есть новый способ объединять словари с помощью конструкции **, которая в главе 9 применяется совершенно по-иному:

>>> first = {'a': 'agony', 'b': 'bliss'}

>>> second = {'b': 'bagels', 'c': 'candy'}

>>> {**first, **second}

{'a': 'agony', 'b': 'bagels', 'c': 'candy'}

Фактически вы можете передать в качестве параметров больше двух словарей:

>>> third = {'d': 'donuts'}

>>> {**first, **third, **second}

{'a': 'agony', 'b': 'bagels', 'd': 'donuts', 'c': 'candy'}

Эти копии являются поверхностными. Обратитесь к подразделу, в котором рассматривается функция deepcopy() (см. подраздел «Копируем все с помощью функции deepcopy()» далее в этой главе), если вам нужно получить полные копии ключей и значений, не связанные с исходными словарями.

Объединяем словари с помощью функции update()

Вы можете использовать функцию update(), чтобы скопировать ключи и значения из одного словаря в другой.

Определим словарь pythons, содержащий имена всех участников:

>>> pythons = {

...     'Chapman': 'Graham',

...     'Cleese': 'John',

...     'Gilliam': 'Terry',

...     'Idle': 'Eric',

...     'Jones': 'Terry',

...     'Palin': 'Michael',

     }

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Gilliam': 'Terry',

'Idle': 'Eric', 'Jones': 'Terry', 'Palin': 'Michael'}

Кроме того, у нас есть еще один словарь — others, содержащий имена других юмористов:

>>> others = { 'Marx': 'Groucho', 'Howard': 'Moe' }

Теперь появляется еще один программист, который решил, что члены словаря others должны быть членами Monty Python:

>>> pythons.update(others)

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Gilliam': 'Terry',

'Idle': 'Eric', 'Jones': 'Terry', 'Palin': 'Michael',

'Marx': 'Groucho', 'Howard': 'Moe'}

Что произойдет, если во втором словаре будут находиться такие же ключи, что и в первом? Победит значение из второго словаря:

>>> first = {'a': 1, 'b': 2}

>>> second = {'b': 'platypus'}

>>> first.update(second)

>>> first

{'a': 1, 'b': 'platypus'}

Удаляем элементы по их ключу с помощью оператора del

Код нашего анонимного программиста pythons.update(others) был корректным технически, но не фактически. Члены словаря others, несмотря на свою известность и чувство юмора, не участвовали в Monty Python. Отменим добавление последних двух элементов:

>>> del pythons['Marx']

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Gilliam': 'Terry',

'Idle': 'Eric', 'Jones': 'Terry', 'Palin': 'Michael',

'Howard': 'Moe'}

>>> del pythons['Howard']

>>> pythons

{'Chapman': 'Graham', 'Cleese': 'John', 'Gilliam': 'Terry',

'Idle': 'Eric', 'Jones': 'Terry', 'Palin': 'Michael'}

Получаем элемент по ключу и удаляем его с помощью функции pop()

В этой функции объединены функции get() и del. Если вы передадите функции pop() ключ в качестве аргумента и такой ключ имеется в словаре, она вернет соответствующее значение и удалит пару. Если ключа в словаре нет, будет сгенерировано исключение:

>>> len(pythons)

6

>>> pythons.pop('Palin')

'Michael'

>>> len(pythons)

5

>>> pythons.pop('Palin')

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

KeyError: 'Palin'

Но если вы передадите функции pop() второй аргумент по умолчанию (как и в случае с функцией get()), словарь не изменится:

>>> pythons.pop('First', 'Hugo')

'Hugo'

>>> len(pythons)

5

Удаляем все элементы с помощью функции clear()

Чтобы удалить все ключи и значения из словаря, вам следует использовать функцию clear() или просто переназначить заданному имени пустой словарь:

>>> pythons.clear()

>>> pythons

{}

>>> pythons = {}

>>> pythons

{}

Проверяем на наличие ключа с помощью оператора in

Если вы хотите узнать, содержится ли в словаре определенный ключ, используйте ключевое слово in. Снова переопределим словарь pythons, но на этот раз пропустим имена одного-двух участников:

>>> pythons = {'Chapman': 'Graham', 'Cleese': 'John',

... 'Jones': 'Terry', 'Palin': 'Michael', 'Idle': 'Eric' }

Теперь проверим, кого мы добавили:

>>> 'Chapman' in pythons

True

>>> 'Palin' in pythons

True

На этот раз мы не забыли о Терри Гиллиаме?

>>> 'Gilliam' in pythons

False

Черт!

Присваиваем значения с помощью оператора =

Как и в случае со списками, если вы внесете в словарь изменение, оно отразится на всех именах, которые на него ссылаются:

>>> signals = {'green': 'go',

... 'yellow': 'go faster',

... 'red': 'smile for the camera'}

>>> save_signals = signals

>>> signals['blue'] = 'confuse everyone'

>>> save_signals

{'green': 'go',

'yellow': 'go faster',

'red': 'smile for the camera',

'blue': 'confuse everyone'}

Копируем значения с помощью функции copy()

Чтобы скопировать ключи и значения из одного словаря в другой и запретить изменяться остальным словарям при изменении данных в одном из них, можно воспользоваться функцией copy():

>>> signals = {'green': 'go',

... 'yellow': 'go faster',

... 'red': 'smile for the camera'}

>>> original_signals = signals.copy()

>>> signals['blue'] = 'confuse everyone'

>>> signals

{'green': 'go',

'yellow': 'go faster',

'red': 'smile for the camera',

'blue': 'confuse everyone'}

>>> original_signals

{'green': 'go',

'yellow': 'go faster',

'red': 'smile for the camera'}

>>>

Эта копия является поверхностной: ее можно применять тогда, когда значения словаря неизменяемы (как в нашем случае). Если значения словаря изменяются, следует использовать функцию deepcopy().

Копируем все с помощью функции deepcopy()

Если бы значением по ключу red в предыдущем примере был список, а не обычная строка:

>>> signals = {'green': 'go',

... 'yellow': 'go faster',

... 'red': ['stop', 'smile']}

>>> signals_copy = signals.copy()

>>> signals

{'green': 'go',

'yellow': 'go faster',

'red': ['stop', 'smile']}

>>> signals_copy

{'green': 'go',

'yellow': 'go faster',

'red': ['stop', 'smile']}

>>>

Изменим одно из значений в списке red:

>>> signals['red'][1] = 'sweat'

>>> signals

{'green': 'go',

'yellow': 'go faster',

'red': ['stop', 'sweat']}

>>> signals_copy

{'green': 'go',

'yellow': 'go faster',

'red': ['stop', 'sweat']}

Вы видите типичную картину, когда при внесении изменений в один объект изменяются оба объекта. Метод copy() копировал значения как есть — это значит, что signal_copy получил тот же список значений для 'red', которые имел и signals.

Решением проблемы является функция deepcopy():

>>> import copy

>>> signals = {'green': 'go',

... 'yellow': 'go faster',

... 'red': ['stop', 'smile']}

>>> signals_copy = copy.deepcopy(signals)

>>> signals

{'green': 'go',

'yellow': 'go faster',

'red': ['stop', 'smile']}

>>> signals_copy

{'green': 'go',

'yellow':'go faster',

'red': ['stop', 'smile']}

>>> signals['red'][1] = 'sweat'

>>> signals

{'green': 'go',

'yellow': 'go faster',

red': ['stop', 'sweat']}

>>> signals_copy

{'green': 'go',

'yellow': 'go faster',

red': ['stop', 'smile']}

Сравниваем словари

Как и в случае со списками и кортежами, рассмотренными в предыдущей главе, словари можно сравнивать с помощью операторов == и !=:

>>> a = {1:1, 2:2, 3:3}

>>> b = {3:3, 1:1, 2:2}

>>> a == b

True

Другие операторы не будут работать:

>>> a = {1:1, 2:2, 3:3}

>>> b = {3:3, 1:1, 2:2}

>>> a <= b

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

TypeError: '<=' not supported between instances of 'dict' and 'dict'

Python сравнивает ключи и значения по одному. Порядок, в котором они создавались, не имеет значения. В этом примере словари a и b равны, за исключением того, что по ключу 1 в словаре а находится список [1,2], а в словаре b — список [1,1].

>>> a = {1: [1, 2], 2: [1], 3:[1]}

>>> b = {1: [1, 1], 2: [1], 3:[1]}

>>> a == b

False

Итерируем по словарям с помощью for и in

Итерирование по словарю (или его функция keys()) возвращает ключи. В этом примере в качестве ключей используются типы карт для настольной игры Clue (за пределами Северной Америки она называется Cluedo):

>>> accusation = {'room': 'ballroom', 'weapon': 'lead pipe',

...               'person': 'Col. Mustard'}

>>> for card in accusation:  #  или for card in accusation.keys():

...     print(card)

...

room

weapon

person

Для того чтобы проитерировать не по ключам, а по значениям, используйте функцию values():

>>> for value in accusation.values():

...     print(value)

...

ballroom

lead pipe

Col. Mustard

Для получения пар «ключ — значение» подходит функция items():

>>> for item in accusation.items():

...     print(item)

...

('room', 'ballroom')

('weapon', 'lead pipe')

('person', 'Col. Mustard')

Присвоить значение кортежа другим переменным можно в один этап. Для каждого кортежа, возвращенного функцией items(), присвоим первый элемент кортежа (ключ) переменной card, а второй элемент (значение) — переменной contents:

>>> for card, contents in accusation.items():

...     print('Card', card, 'has the contents', contents)

...

Card weapon has the contents lead pipe

Card person has the contents Col. Mustard

Card room has the contents ballroom

Включения словарей

У словарей также существуют включения.

Простейшая форма выглядит знакомо:

{выражениедляключа : выражениедлязначения for выражение in итерабельныйобъект}

>>> word = 'letters'

>>> letter_counts = {letter: word.count(letter) for letter in word}

>>> letter_counts

{'l': 1, 'e': 2, 't': 2, 'r': 1, 's': 1}

Мы проходим в цикле по каждой из семи букв строки 'letters' и считаем, сколько раз буква встречается. Дважды использовать функцию word.count(letter) — значит впустую тратить время, поскольку нам придется по два раза посчитать буквы e и t. Но это ничему не навредит, потому что после второго вызова этой функции для буквы е мы всего лишь заменим существующую запись в словаре. То же самое верно и для буквы t. Следующий фрагмент больше соответствует «питонскому» стилю:

>>> word = 'letters'

>>> letter_counts = {letter: word.count(letter) for letter in set(word)}

>>> letter_counts

{'t': 2, 'l': 1, 'e': 2, 'r': 1, 's': 1}

Порядок ключей словаря изменился по сравнению с предыдущим примером, поскольку вызов set(word) возвращает буквы в другом порядке.

По аналогии со списковыми включениями для генератора словарей также можно использовать условные проверки if и более одного блока for:

{выражение для ключа : выражение для значения for выражение in итерабельныйобъект if условие}

 

>>> vowels = 'aeiou'

>>> word = 'onomatopoeia'

>>> vowel_counts = {letter: word.count(letter) for letter in set(word)

        if letter in vowels}

>>> vowel_counts

{'e': 1, 'i': 1, 'o': 4, 'a': 2}

Вы сможете найти дополнительные примеры использования генераторов словарей в PEP-274 ().

Множества

Множество похоже на словарь, в котором значения отброшены, а оставлены только ключи. Как и в словаре, ключи должны быть уникальными. Вы используете множество, если хотите знать только, существует что-то или нет, а другая информация вам неважна. Это как сумка с ключами. Если же вам нужно прикрепить к ключу некую информацию, воспользуйтесь словарем.

Было время, когда теорию множеств преподавали в некоторых начальных школах наряду с основами математики. Если в вашей школе такого не было (или было, но вы в это время смотрели в окно), на рис. 8.1 можно увидеть, как объединяются и пересекаются мно­жества.

146402.png 

Рис. 8.1. Обычные операции с множествами

Предположим, вы хотите объединить два множества, у которых есть несколько общих ключей. Поскольку множество должно содержать только уникальные значения, объединение двух множеств будет иметь всего лишь один такой одинаковый ключ. Пустое множество — это множество, содержащее ноль элементов. На рис. 8.1 примером пустого множества будут женские имена, начинающиеся с буквы Х.

Создаем множество с помощью функции set()

Чтобы создать множество, воспользуйтесь функцией set(). Можно также разместить в фигурных скобках одно или несколько разделенных запятыми значений, как показано здесь:

>>> empty_set = set()

>>> empty_set

set()

>>> even_numbers = {0, 2, 4, 6, 8}

>>> even_numbers

{0, 2, 4, 6, 8}

>>> odd_numbers = {1, 3, 5, 7, 9}

>>> odd_numbers

{1, 3, 5, 7, 9}

Порядок ключей в множестве не имеет значения.

109108.png

Поскольку пустые квадратные скобки [] создают пустой список, можно было бы предположить, что пустые фигурные скобки {} создают пустое множество. Вместо этого пустые фигурные скобки создают пустой словарь. Именно поэтому интерпретатор выводит пустое множество как set() вместо {}. Почему так происходит? Словари появились в Python раньше и успели захватить фигурные скобки в свое распоряжение. А владение — это девять десятых законного права.

Преобразуем другие типы данных с помощью функции set()

Вы можете создать множество из списка, строки, кортежа или словаря, отбрасывая любые повторяющиеся значения.

Для начала взглянем на строку, в которой отдельные буквы встречаются несколько раз:

>>> set('letters')

{'l', 'r', 's', 't', 'e'}

Обратите внимание, что множество содержит только по одной e и t, хотя в слове letters они встречаются дважды.

Создадим множество из списка:

>>> set(['Dasher', 'Dancer', 'Prancer', 'Mason-Dixon'])

{'Dancer', 'Dasher', 'Mason-Dixon', 'Prancer'}

А теперь из кортежа:

>>> set(('Ummagumma', 'Echoes', 'Atom Heart Mother'))

{'Ummagumma', 'Atom Heart Mother', 'Echoes'}

Когда вы передаете функции set() словарь, она возвращает только ключи:

>>> set({'apple': 'red', 'orange': 'orange', 'cherry': 'red'})

{'cherry', 'orange', 'apple'}

Получаем длину множества с помощью функции len()

Пересчитаем наших оленей:

>>> reindeer = set( ['Dasher', 'Dancer', 'Prancer', 'Mason-Dixon'] )

>>> len(reindeer)

4

Добавляем элемент с помощью функции add()

Добавим во множество еще один элемент с помощью метода add():

>>> s = set((1,2,3))

>>> s

{1, 2, 3}

>>> s.add(4)

>>> s

{1, 2, 3, 4}

Удаляем элемент с помощью функции remove()

Вы можете удалить выбранное значение из множества:

>>> s = set((1,2,3))

>>> s.remove(3)

>>> s

{1, 2}

Итерируем по множествам с помощью for и in

Как и в случае со словарями, вы можете проитерировать по всем элементам множества:

>>> furniture = set(('sofa', 'ottoman', 'table'))

>>> for piece in furniture:

...     print(piece)

...

ottoman

table

sofa

Проверяем на наличие значения с помощью оператора in

Такое использование множеств — самое распространенное. Мы создадим словарь, который называется drinks. Каждый ключ будет названием коктейля, а соответствующее значение — множеством с ингредиентами этого напитка:

>>> drinks = {

...     'martini': {'vodka', 'vermouth'},

...     'black russian': {'vodka', 'kahlua'},

...     'white russian': {'cream', 'kahlua', 'vodka'},

...     'manhattan': {'rye', 'vermouth', 'bitters'},

...     'screwdriver': {'orange juice', 'vodka'}

...     }

Хотя и словарь, и множества заключаются в фигурные скобки ({ и }), множество — это всего лишь набор значений, а словарь содержит пары «ключ — значение».

Какой из коктейлей содержит водку?

>>> for name, contents in drinks.items():

...     if 'vodka' in contents:

...         print(name)

...

screwdriver

martini

black russian

white russian

Мы хотим выпить коктейль с водкой, но не переносим лактозу, а вермут на вкус как керосин:

>>> for name, contents in drinks.items():

...     if 'vodka' in contents and not ('vermouth' in contents or

...         'cream' in contents):

...         print(name)

...

screwdriver

black russian

Перепишем этот пример чуть более кратко в следующем подразделе.

Комбинации и операторы

Что, если вам нужно проверить наличие сразу нескольких значений множества? Предположим, вы хотите найти какой-нибудь напиток с апельсиновым соком или вермутом. Для этого мы используем операторпересечения множеств (&):

>>> for name, contents in drinks.items():

...     if contents & {'vermouth', 'orange juice'}:

...         print(name)

...

screwdriver

martini

manhattan

Результатом работы оператора & является множество со всеми элементами из обоих сравниваемых списков. Если ни один из заданных ингредиентов не содержится в предлагаемых коктейлях, оператор & вернет пустое множество. Этот результат можно считать равным False.

Теперь перепишем пример из предыдущего подраздела, когда мы хотели водки, не смешанной со сливками или вермутом:

>>> for name, contents in drinks.items():

...     if 'vodka' in contents and not contents & {'vermouth', 'cream'}:

...         print(name)

...

screwdriver

black russian

Сохраним множества ингредиентов для этих двух напитков в переменных, чтобы не пришлось слишком много печатать в дальнейших примерах:

>>> bruss = drinks['black russian']

>>> wruss = drinks['white russian']

Ниже приведены примеры всех операторов множеств. У одних есть специальная пунктуация, у других — специальные функции, у третьих — и то и другое. Мы будем использовать тестовые множества а (содержит элементы 1 и 2) и b (содержит элементы 2 и 3):

>>> a = {1, 2}

>>> b = {2, 3}

Как вы видели ранее, пересечение (элементы, общие для обоих множеств) можно получить с помощью особого пунктуационного символа &. Функция intersection() делает то же самое:

>>> a & b

{2}

>>> a.intersection(b)

{2}

В данном фрагменте используются сохраненные нами переменные:

>>> bruss & wruss

{'kahlua', 'vodka'}

В следующем примере мы получаем объединение (члены обоих множеств), используя оператор | или функцию множества union():

>>> a | b

{1, 2, 3}

>>> a.union(b)

{1, 2, 3}

И алкогольная версия:

>>> bruss | wruss

{'cream', 'kahlua', 'vodka'}

Разность множеств (члены только первого множества, но не второго) можно получить с помощью символа — или функции difference():

>>> a – b

{1}

>>> a.difference(b)

{1}

>>> bruss – wruss

set()

>>> wruss – bruss

{'cream'}

Самыми распространенными операциями с множествами являются объединение, пересечение и разность. Для полноты картины я включил в этот подраздел и остальные операции, но, возможно, вам никогда не придется их использовать.

Для выполнения исключающего ИЛИ (элементы или первого, или второго множества, но не общие) используйте оператор ^ или функцию symmetric_difference():

>>> a ^ b

{1, 3}

>>> a.symmetric_difference(b)

{1, 3}

В этом примере определяется эксклюзивный ингредиент для русских напитков:

>>> bruss ^ wruss

{'cream'}

Проверить, является ли одно множество подмножеством другого (когда все члены первого множества являются членами второго), можно с помощью оператора <= или функции issubset():

>>> a <= b

False

>>> a.issubset(b)

False

Добавление сливок в коктейль «Черный русский» сделает его «Белым русским», поэтому wruss является подмножеством bruss:

>>> bruss <= wruss

True

Является ли любое множество подмножеством самого себя? Ага.

>>> a <= a

True

>>> a.issubset(a)

True

Для того чтобы стать собственным подмножеством, второе множество должно содержать все члены первого и несколько других. Определяется это с помощью оператора <, как показано в следующем примере:

>>> a < b

False

>>> a < a

False

 

>>> bruss < wruss

True

Надмножество противоположно подмножеству (все члены второго множества являются также членами первого). Для определения этого используется оператор >= или функция issuperset():

>>> a >= b

False

>>> a.issuperset(b)

False

 

>>> wruss >= bruss

True

Любое множество является надмножеством самого себя:

>>> a >= a

True

>>> a.issuperset(a)

True

И наконец, вы можете встретить правильное надмножество (первое множество содержит все члены второго и несколько других) с помощью оператора >, как показано здесь:

>>> a > b

False

 

>>> wruss > bruss

True

Множество не может быть правильным надмножеством самого себя:

>>> a > a

False

Включение множества

Никто не хочет оставаться в стороне, поэтому даже у множеств есть включения. Простейшая версия выглядит как включение списка или словаря, которые вы только что видели:

{ выражение for выражение in итерабельный объект}

Здесь также могут быть необязательные проверки условий:

{ выражение for выражение in итерабельный объект if условие }

 

>>> a_set = {number for number in range(1,6) if number % 3 == 1}

>>> a_set

{1, 4}

Создаем неизменяемое множество с помощью функции frozenset()

Если вы хотите создать множество, которое нельзя будет изменить, вызовите функцию frozenset(), передав в нее любой итерабельный аргумент:

>>> frozenset([3, 2, 1])

frozenset({1, 2, 3})

>>> frozenset(set([2, 1, 3]))

frozenset({1, 2, 3})

>>> frozenset({3, 1, 2})

frozenset({1, 2, 3})

>>> frozenset( (2, 3, 1) )

frozenset({1, 2, 3})

Достаточно ли «заморозилось» наше множество?

>>> fs = frozenset([3, 2, 1])

>>> fs

frozenset({1, 2, 3})

>>> fs.add(4)

Traceback (most recent call last):

  File "<stdin>", line 1, in <module>

AttributeError: 'frozenset' object has no attribute 'add'

Да, множество хорошо «заморозилось».

Структуры данных, которые мы уже рассмотрели

Напомню, структуры данных создаются следующим образом:

список — с помощью квадратных скобок ([]);

• кортеж — с помощью запятых (и опциональных скобок);

словарь и множество — с помощью фигурных скобок ({}).

Во всех случаях, за исключением множеств, вы получаете доступ к отдельному элементу с помощью квадратных скобок. Для списка и кортежа значение, находящееся в квадратных скобках, является целочисленным смещением. Для словаря же оно является ключом. Везде результатом будет значение. Для множества: значение либо есть, либо нет; ключей и индексов нет.

>>> marx_list = ['Groucho', 'Chico', 'Harpo']

>>> marx_tuple = 'Groucho', 'Chico', 'Harpo'

>>> marx_dict = {'Groucho': 'banjo', 'Chico': 'piano', 'Harpo': 'harp'}

>>> marx_set = {'Groucho', 'Chico', 'Harpo'}

>>> marx_list[2]

'Harpo'

>>> marx_tuple[2]

'Harpo'

>>> marx_dict['Harpo']

'harp'

>>> 'Harpo' in marx_list

True

>>> 'Harpo' in marx_tuple

True

>>> 'Harpo' in marx_dict

True

>>> 'Harpo' in marx_set

True

Создание крупных структур данных

Ранее мы работали с простыми булевыми значениями, числами и строками. Теперь же мы работаем со списками, кортежами, множествами и словарями. Вы можете объединить эти встроенные структуры данных в свои более крупные и сложные структуры. Начнем с трех разных списков:

>>> marxes = ['Groucho', 'Chico', 'Harpo']

>>> pythons = ['Chapman', 'Cleese', 'Gilliam', 'Jones', 'Palin']

>>> stooges = ['Moe', 'Curly', 'Larry']

Мы можем создать кортеж, элементами которого станут все эти списки:

>>> tuple_of_lists = marxes, pythons, stooges

>>> tuple_of_lists

(['Groucho', 'Chico', 'Harpo'],

['Chapman', 'Cleese', 'Gilliam', 'Jones', 'Palin'],

['Moe', 'Curly', 'Larry'])

Можем также создать список, состоящий из трех списков:

>>> list_of_lists = [marxes, pythons, stooges]

>>> list_of_lists

[['Groucho', 'Chico', 'Harpo'],

['Chapman', 'Cleese', 'Gilliam', 'Jones', 'Palin'],

['Moe', 'Curly', 'Larry']]

Словарь из списков также возможен. В этом примере используем название группы комиков в качестве ключа, а список ее участников — в качестве значения:

dict_of_lists = {'Marxes': marxes, 'Pythons': pythons, 'Stooges': stooges}

>> dict_of_lists

{'Marxes': ['Groucho', 'Chico', 'Harpo'],

'Pythons': ['Chapman', 'Cleese', 'Gilliam', 'Jones', 'Palin'],

'Stooges': ['Moe', 'Curly', 'Larry']}

Ваши единственные ограничения — только сами типы данных. Например, ключи словаря должны быть неизменяемыми, поэтому списки, словари и множества не могут быть ключами для другого словаря. Но кортеж может быть. Создадим, к примеру, алфавитный указатель достопримечательностей, основываясь на GPS-координатах (широте, долготе и высоте). В главе 21 вы найдете еще несколько примеров работы с картами:

>>> houses = {

        (44.79, -93.14, 285): 'My House',

        (38.89, -77.03, 13): 'The White House'

        }

Читайте далее

Мы вернемся к структурам кода. Покажем, как «завернуть» код в функцию и как работать с исключениями, когда что-то идет не так.

Упражнения

8.1. Создайте англо-французский словарь с названием e2f и выведите его на экран. Вот ваши первые слова: dog/chien, cat/chat и walrus/morse.

8.2. Используя словарь e2f, выведите французский вариант слова walrus.

8.3. Создайте французско-английский словарь f2e на основе словаря e2f. Используйте метод items.

8.4. Используя словарь f2e, выведите английский вариант слова chien.

8.5. Выведите на экран множество английских слов из ключей словаря e2f.

8.6. Создайте многоуровневый словарь life. Используйте следующие строки для ключей верхнего уровня: 'animals', 'plants' и 'other'. Сделайте так, чтобы ключ 'animals' ссылался на другой словарь, имеющий ключи 'cats', 'octopi' и 'emus'. Сделайте так, чтобы ключ 'cats' ссылался на список строк со значениями 'Henri', 'Grumpy' и 'Lucy'. Остальные ключи должны ссылаться на пустые словари.

8.7. Выведите на экран высокоуровневые ключи словаря life.

8.8. Выведите на экран ключи life['animals'].

8.9. Выведите значения life['animals']['cats'].

8.10. Используйте генератор словаря, чтобы создать словарь squares. Используйте range(10), чтобы получить ключи. В качестве значений используйте возведенное в квадрат значение каждого ключа.

8.11. Используйте генератор множества, чтобы создать множество odd из нечетных чисел диапазона range(10).

8.12. Используйте включение генератора, чтобы вернуть строку 'Got' и числа из диапазона range(10). Итерируйте по этой конструкции с помощью цикла for.

8.13. Используйте функцию zip(), чтобы создать словарь из кортежа ключей ('optimist', 'pessimist', 'troll') и кортежа значений ('Theglassishalffull', 'Theglassishalfempty', 'Howdidyougetaglass?').

8.14. Используйте функцию zip(), чтобы создать словарь с именем movies, в котором объединены списки titles=['CreatureofHabit','CrewelFate','SharksOnaPlane'] и plots=['Anunturnsintoamonster','Ahauntedyarnshop','Checkyourexits'].

Очень похоже на финальный счет матча «Стронций» — «Углерод».

Однако, перефразируя Граучо Маркса, «я бы не хотел состоять в клубе, в который принимают таких людей, как я».

Назад: Глава 7. Кортежи и списки
Дальше: Глава 9. Функции

dofermerdat
этот. породы кроликов с фотографиями мясныефермер ру форум рассадакрупнейшие сельскохозяйственные районы зарубежной европыкрс мясо