Словари в Python

Словари в Python

Python предоставляет еще один составнойdata type, называемыйdictionary, который похож на список в том смысле, что представляет собой набор объектов.

Here’s what you’ll learn in this tutorial: Вы познакомитесь с основными характеристиками словарей Python и узнаете, как получить доступ к данным словаря и управлять ими. После того, как вы закончили это руководство, у вас должно быть четкое представление о том, когда словарь является подходящим типом данных для использования, и как это сделать.

Словари и списки имеют следующие характеристики:

  • Оба изменчивы.

  • Оба динамические. Они могут расти и уменьшаться по мере необходимости.

  • Оба могут быть вложенными. Список может содержать другой список. Словарь может содержать другой словарь. Словарь может также содержать список, и наоборот.

Словари отличаются от списков в первую очередь тем, как осуществляется доступ к элементам:

  • Доступ к элементам списка осуществляется по их положению в списке посредством индексации.

  • Доступ к элементам словаря осуществляется через ключи.

__ Take the Quiz: Проверьте свои знания с помощью нашей интерактивной викторины «Словари Python». По окончании вы получите оценку, чтобы вы могли отслеживать прогресс в обучении с течением времени:

Определение словаря

Словари - это реализация Python структуры данных, более известная как ассоциативный массив. Словарь состоит из набора пар ключ-значение. Каждая пара ключ-значение отображает ключ на соответствующее значение.

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

d = {
    : ,
    : ,
      .
      .
      .
    : 
}

Следующее определяет словарь, который сопоставляет местоположение с названием соответствующей бейсбольной команды Высшей лиги:

>>>

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }

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

d = dict([
    (, ),
    (, , )
])

MLB_team также можно определить следующим образом:

>>>

>>> MLB_team = dict([
...     ('Colorado', 'Rockies'),
...     ('Boston', 'Red Sox'),
...     ('Minnesota', 'Twins'),
...     ('Milwaukee', 'Brewers'),
...     ('Seattle', 'Mariners')
... ])

Если значения ключа являются простыми строками, они могут быть указаны в качестве аргументов ключевых слов. Итак, вот еще один способ определитьMLB_team:

>>>

>>> MLB_team = dict(
...     Colorado='Rockies',
...     Boston='Red Sox',
...     Minnesota='Twins',
...     Milwaukee='Brewers',
...     Seattle='Mariners'
... )

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

>>>

>>> type(MLB_team)


>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}

Записи в словаре отображаются в порядке их определения. Но это не имеет значения, когда дело доходит до их извлечения. Элементы словаря не доступны по числовому индексу:

>>>

>>> MLB_team[1]
Traceback (most recent call last):
  File "", line 1, in 
    MLB_team[1]
KeyError: 1

Доступ к значениям словаря

Конечно, элементы словаря должны быть как-то доступны. Если вы не получаете их по индексу, то как вы их получаете?

Значение извлекается из словаря путем указания соответствующего ключа в квадратных скобках ([]):

>>>

>>> MLB_team['Minnesota']
'Twins'
>>> MLB_team['Colorado']
'Rockies'

Если вы ссылаетесь на ключ, которого нет в словаре, Python вызывает исключение:

>>>

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "", line 1, in 
    MLB_team['Toronto']
KeyError: 'Toronto'

Добавление записи в существующий словарь - это просто вопрос назначения нового ключа и значения:

>>>

>>> MLB_team['Kansas City'] = 'Royals'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners', 'Kansas City': 'Royals'}

Если вы хотите обновить запись, вы можете просто присвоить новое значение существующему ключу:

>>>

>>> MLB_team['Seattle'] = 'Seahawks'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Seahawks', 'Kansas City': 'Royals'}

Чтобы удалить запись, используйте операторdel, указав ключ для удаления:

>>>

>>> del MLB_team['Seattle']
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Kansas City': 'Royals'}

Прочь, Сихокс! Ты команда НФЛ.

Словарь ключи против Список индексов

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

>>>

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "", line 1, in 
    MLB_team['Toronto']
KeyError: 'Toronto'

>>> MLB_team[1]
Traceback (most recent call last):
  File "", line 1, in 
    MLB_team[1]
KeyError: 1

На самом деле это та же ошибка. В последнем случае[1] выглядит как числовой индекс, но это не так.

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

>>>

>>> d = {0: 'a', 1: 'b', 2: 'c', 3: 'd'}
>>> d
{0: 'a', 1: 'b', 2: 'c', 3: 'd'}

>>> d[0]
'a'
>>> d[2]
'c'

В выраженияхMLB_team[1],d[0] иd[2] числа в квадратных скобках выглядят так, как если бы они могли быть индексами. Но они не имеют ничего общего с порядком элементов в словаре. Python интерпретирует их как словарные ключи. Если вы определите этот же словарь в обратном порядке, вы все равно получите те же значения, используя те же ключи:

>>>

>>> d = {3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> d
{3: 'd', 2: 'c', 1: 'b', 0: 'a'}

>>> d[0]
'a'
>>> d[2]
'c'

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

>>>

>>> type(d)


>>> d[-1]
Traceback (most recent call last):
  File "", line 1, in 
    d[-1]
KeyError: -1

>>> d[0:2]
Traceback (most recent call last):
  File "", line 1, in 
    d[0:2]
TypeError: unhashable type: 'slice'

>>> d.append('e')
Traceback (most recent call last):
  File "", line 1, in 
    d.append('e')
AttributeError: 'dict' object has no attribute 'append'

Note: Хотя доступ к элементам в словаре не зависит от порядка, Python гарантирует, что порядок элементов в словаре сохраняется. При отображении элементы будут отображаться в том порядке, в котором они были определены, и итерация по клавишам также будет происходить в этом порядке. Элементы, добавленные в словарь, добавляются в конце. Если элементы удалены, порядок оставшихся элементов сохраняется.

Вы можете рассчитывать только на это сохранение порядка совсем недавно. Это былоadded as a part of the Python language specification in version 3.7. Тем не менее, это было верно и для версии 3.6 - случайно в результате реализации, но не гарантируется спецификацией языка.

Построение словаря постепенно

Определение словаря с использованием фигурных скобок и списка пар ключ-значение, как показано выше, хорошо, если вы заранее знаете все ключи и значения. Но что, если вы хотите построить словарь на лету?

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

>>>

>>> person = {}
>>> type(person)


>>> person['fname'] = 'Joe'
>>> person['lname'] = 'Fonebone'
>>> person['age'] = 51
>>> person['spouse'] = 'Edna'
>>> person['children'] = ['Ralph', 'Betty', 'Joey']
>>> person['pets'] = {'dog': 'Fido', 'cat': 'Sox'}

Как только словарь создан таким образом, к его значениям обращаются так же, как и к любому другому словарю:

>>>

>>> person
{'fname': 'Joe', 'lname': 'Fonebone', 'age': 51, 'spouse': 'Edna',
'children': ['Ralph', 'Betty', 'Joey'], 'pets': {'dog': 'Fido', 'cat': 'Sox'}}

>>> person['fname']
'Joe'
>>> person['age']
51
>>> person['children']
['Ralph', 'Betty', 'Joey']

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

>>>

>>> person['children'][-1]
'Joey'
>>> person['pets']['cat']
'Sox'

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

Так же, как значения в словаре не обязательно должны быть одного типа, ключи не должны:

>>>

>>> foo = {42: 'aaa', 2.78: 'bbb', True: 'ccc'}
>>> foo
{42: 'aaa', 2.78: 'bbb', True: 'ccc'}

>>> foo[42]
'aaa'
>>> foo[2.78]
'bbb'
>>> foo[True]
'ccc'

Здесь один из ключей - целое число, один - число с плавающей запятой, а другой - логическое значение. Не очевидно, как это было бы полезно, но вы никогда не знаете.

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

Вы можете использовать словари для самых разных целей, потому что для ключей и значений допускается так мало ограничений. Но есть некоторые. Читать дальше!

Ограничения на словарные ключи

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

>>>

>>> foo = {42: 'aaa', 2.78: 'bbb', True: 'ccc'}
>>> foo
{42: 'aaa', 2.78: 'bbb', True: 'ccc'}

Вы даже можете использовать встроенные объекты, такие как типы и функции:

>>>

>>> d = {int: 1, float: 2, bool: 3}
>>> d
{: 1, : 2, : 3}
>>> d[float]
2

>>> d = {bin: 1, hex: 2, oct: 3}
>>> d[oct]
3

Однако существует пара ограничений, которым должны следовать ключи словаря.

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

Вы видели выше, что когда вы присваиваете значение уже существующему ключу словаря, он не добавляет ключ во второй раз, а заменяет существующее значение:

>>>

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }

>>> MLB_team['Minnesota'] = 'Timberwolves'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Timberwolves',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}

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

>>>

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Timberwolves',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners',
...     'Minnesota': 'Twins'
... }
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}

Прочь, Лесные волки! Ты команда НБА. Вроде, как бы, что-то вроде.

Во-вторых, ключ словаря должен иметь тип, который является неизменным. Вы уже видели примеры, когда некоторые из неизменяемых типов, с которыми вы знакомы, - integer, float, string и Boolean - служили в качестве ключей словаря.

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

>>>

>>> d = {(1, 1): 'a', (1, 2): 'b', (2, 1): 'c', (2, 2): 'd'}
>>> d[(1,1)]
'a'
>>> d[(2,1)]
'c'

(Вспомните из обсужденияtuples, что одно из объяснений использования кортежа вместо списка состоит в том, что существуют обстоятельства, когда требуется неизменяемый тип. Это один из них.)

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

>>>

>>> d = {[1, 1]: 'a', [1, 2]: 'b', [2, 1]: 'c', [2, 2]: 'd'}
Traceback (most recent call last):
  File "", line 1, in 
    d = {[1, 1]: 'a', [1, 2]: 'b', [2, 1]: 'c', [2, 2]: 'd'}
TypeError: unhashable type: 'list'

Technical Note: Почему в сообщении об ошибке написано «не хэшируемое»?

Технически, не совсем правильно говорить, что объект должен быть неизменным для использования в качестве словарного ключа. Точнее, объект должен бытьhashable, что означает, что он может быть передан хеш-функции. Хеш-функция принимает данные произвольного размера и сопоставляет их с относительно более простым значением фиксированного размера, называемымhash value (или просто хешем), которое используется для поиска и сравнения в таблице.

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

>>>

>>> hash('foo')
11132615637596761

>>> hash([1, 2, 3])
Traceback (most recent call last):
  File "", line 1, in 
TypeError: unhashable type: 'list'

Все встроенные неизменяемые типы, о которых вы узнали до сих пор, являются хэшируемыми, а типы изменяемых контейнеров (списки и словари) - нет. Таким образом, для настоящих целей вы можете думать о hashable и неизменяемом как о более или менее синонимичном.

В будущих уроках вы встретите изменчивые объекты, которые также можно хэшировать.

Ограничения на значения словаря

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

Также нет ограничений в отношении определенного значения, появляющегося в словаре несколько раз:

>>>

>>> d = {0: 'a', 1: 'a', 2: 'a', 3: 'a'}
>>> d
{0: 'a', 1: 'a', 2: 'a', 3: 'a'}
>>> d[0] == d[1] == d[2]
True

Операторы и встроенные функции

Вы уже познакомились со многими операторами и встроенными функциями, которые можно использовать сstrings,lists иtuples. Некоторые из них также работают со словарями.

Например, операторыin иnot in возвращаютTrue илиFalse в зависимости от того, встречается ли указанный операнд как ключ в словаре:

>>>

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }

>>> 'Milwaukee' in MLB_team
True
>>> 'Toronto' in MLB_team
False
>>> 'Toronto' not in MLB_team
True

Вы можете использовать операторin вместе с оценкой короткого замыкания, чтобы избежать появления ошибки при попытке доступа к ключу, которого нет в словаре:

>>>

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "", line 1, in 
    MLB_team['Toronto']
KeyError: 'Toronto'

>>> 'Toronto' in MLB_team and MLB_team['Toronto']
False

Во втором случае из-за оценки короткого замыкания выражениеMLB_team['Toronto'] не оценивается, поэтому исключениеKeyError не возникает.

Функцияlen() возвращает количество пар ключ-значение в словаре:

>>>

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }
>>> len(MLB_team)
5

Встроенные словарные методы

Как и в случае со строками и списками, существует несколько встроенных методов, которые можно вызывать в словарях. На самом деле, в некоторых случаях методы списка и словаря имеют одно и то же имя. (В обсуждении объектно-ориентированного программирования вы увидите, что для разных типов вполне допустимо иметь методы с одинаковым именем.)

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

d.clear()

Очищает словарь.

d.clear() очищает словарьd от всех пар ключ-значение:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}

>>> d.clear()
>>> d
{}

d.get([, ])

Возвращает значение для ключа, если оно существует в словаре.

Метод.get() словаря Python обеспечивает удобный способ получения значения ключа из словаря без предварительной проверки существования ключа и без возникновения ошибки.

d.get(<key>) ищет в словареd<key> и возвращает соответствующее значение, если оно найдено. Если<key> не найден, возвращаетсяNone:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}

>>> print(d.get('b'))
20
>>> print(d.get('z'))
None

Если<key> не найден и указан необязательный аргумент<default>, это значение возвращается вместоNone:

>>>

>>> print(d.get('z', -1))
-1

d.items()

Возвращает список пар ключ-значение в словаре.

d.items() возвращает список кортежей, содержащих пары ключ-значение вd. Первый элемент в каждом кортеже - это ключ, а второй элемент - это значение ключа:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}

>>> list(d.items())
[('a', 10), ('b', 20), ('c', 30)]
>>> list(d.items())[1][0]
'b'
>>> list(d.items())[1][1]
20

d.keys()

Возвращает список ключей в словаре.

d.keys() возвращает список всех ключей вd:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}

>>> list(d.keys())
['a', 'b', 'c']

d.values()

Возвращает список значений в словаре.

d.values() возвращает список всех значений вd:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}

>>> list(d.values())
[10, 20, 30]

Любые повторяющиеся значения вd будут возвращаться столько раз, сколько они встречаются:

>>>

>>> d = {'a': 10, 'b': 10, 'c': 10}
>>> d
{'a': 10, 'b': 10, 'c': 10}

>>> list(d.values())
[10, 10, 10]

Technical Note: Методы.items(),.keys() и.values() фактически возвращают то, что называетсяview object. Объект просмотра словаря более или менее похож на окно с ключами и значениями. В практических целях вы можете рассматривать эти методы как возвращающие списки ключей и значений словаря.

d.pop([, ])

Удаляет ключ из словаря, если он присутствует, и возвращает его значение.

Если<key> присутствует вd,d.pop(<key>) удаляет<key> и возвращает связанное с ним значение:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}

>>> d.pop('b')
20
>>> d
{'a': 10, 'c': 30}

d.pop(<key>) вызывает исключениеKeyError, если<key> не находится вd:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}

>>> d.pop('z')
Traceback (most recent call last):
  File "", line 1, in 
    d.pop('z')
KeyError: 'z'

Если<key> отсутствует вd и указан необязательный аргумент<default>, то возвращается это значение, и исключение не возникает:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d.pop('z', -1)
-1
>>> d
{'a': 10, 'b': 20, 'c': 30}

d.popitem()

Удаляет пару ключ-значение из словаря.

d.popitem() удаляет случайную произвольную пару ключ-значение изd и возвращает ее как кортеж:

>>>

>>> d = {'a': 10, 'b': 20, 'c': 30}

>>> d.popitem()
('c', 30)
>>> d
{'a': 10, 'b': 20}

>>> d.popitem()
('b', 20)
>>> d
{'a': 10}

Еслиd пусто,d.popitem() вызывает исключениеKeyError:

>>>

>>> d = {}
>>> d.popitem()
Traceback (most recent call last):
  File "", line 1, in 
    d.popitem()
KeyError: 'popitem(): dictionary is empty'

d.update()

Объединяет словарь с другим словарем или с итерацией пар ключ-значение.

Если<obj> - словарь,d.update(<obj>) объединяет записи из<obj> вd. Для каждого ключа в<obj>:

  • Если ключ отсутствует вd, пара ключ-значение из<obj> добавляется кd.

  • Если ключ уже присутствует вd, соответствующее значение вd для этого ключа обновляется до значения из<obj>.

Вот пример, показывающий два словаря, объединенных вместе:

>>>

>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d2 = {'b': 200, 'd': 400}

>>> d1.update(d2)
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}

В этом примере ключ'b' уже существует вd1, поэтому его значение обновляется до200, значение для этого ключа изd2. Однако вd1 нет ключа'd', поэтому пара ключ-значение добавляется изd2.

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

>>>

>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d1.update([('b', 200), ('d', 400)])
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}

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

>>>

>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d1.update(b=200, d=400)
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}

Заключение

В этом руководстве вы рассмотрели основные свойства Pythondictionary и узнали, как получить доступ и управлять данными словаря.

Lists иdictionaries - два наиболее часто используемых типа Python. Как вы видели, они имеют несколько сходств, но различаются по способу доступа к их элементам. Доступ к элементам списков осуществляется по числовому индексу в зависимости от порядка, а к элементам словаря - по ключу.

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

Далее вы узнаете о Pythonsets. Набор является другим составным типом данных, но он сильно отличается от списка или словаря.

__ Take the Quiz: Проверьте свои знания с помощью нашей интерактивной викторины «Словари Python». По окончании вы получите оценку, чтобы вы могли отслеживать прогресс в обучении с течением времени: