okpython.net
Все для начинающих

Словари в Python

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

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

Словарь (от англ. dictionary) – это именованная изменяемая неупорядоченная коллекция объектов произвольного типа. Сами объекты называются элементами словаря, а доступ к ним может быть получен при помощи ключей словаря. Иногда словари еще называют ассоциативными массивами или хешами.

Так же как и списки, словари нам нужны для хранения произвольных объектов. Однако, если в списках мы используем для доступа к ним целочисленные индексы, которые определяют позицию элемента в последовательности, то в словарях это делается при помощи ключей, представляющих собой некоторые неизменяемые значения (например, числа, строки или кортежи), которые позволяют однозначно идентифицировать элементы словаря (см. пример №1).

Код Результат pythonCodes
# Сохраним список в переменной.
li = ['abc', 123, (1, 2, 3)]
# Выводим эл-ты списка.
print(li[0], li[1], li[2], end='\n\n')		

# Сохраняем те же объекты, но в словаре.
d = {'str': 'abc', 'num': 123, 'tuple': (1, 2, 3)}
# Выводим эл-ты на экран.
print(d['str'], d['num'], d['tuple'])
abc 123 (1, 2, 3)

abc 123 (1, 2, 3)




		
			

Пример №1. Используем словарь для хранения объектов.

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

Создание словарей в Python

Для того, чтобы создать литерал словаря в Python, нужно внутри фигурных скобок через запятую перечислить пары «ключ: значение», отделив ключи от значений двоеточием (см. пример №2). В случае необходимости последний элемент словаря также разрешается завершать запятой. Это никак не повлияет на количество элементов словаря, а значит и его длину.

Код Результат pythonCodes
# Получаем пустой словарь.
dict_1 = {}
# Выведет {}.
print(dict_1, end='\n\n')        

# Пары «ключ: значение» перечисляем через запятую.
dict_2 = {'язык': 'Python', 'версия': 3.9}
# Выведет {'язык': 'Python', 'версия': 3.9}.
print(dict_2, end='\n\n') 	

# Последнюю запятую можно не опускать.
dict_3 = {1: 'один', 2: 'два',}
# Выведет {1: 'один', 2: 'два'}.
print(dict_3, end='\n\n')

# Эле-ми могут быть любые объекты любой вложенности.
dict_4 = {'li': ['a', {0: (False, True), 1: None}],
          'tpl': (1, 2, 3)}
print(dict_4)
{}

{'язык': 'Python', 'версия': 3.9}

{1: 'один', 2: 'два'}

{'li': ['a', {0: (False, True), 1: None}], 'tpl': (1, 2, 3)}



 
 
 




		
			

Пример №2. Создание словарей в Python (часть 1).

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

Создать словарь можно также при помощи встроенного конструктора типа dict(). Если использовать его без аргументов, то он вернет нам пустой словарь {}. Если передать конструктору через запятую пары key_name_1 = val_1, key_name_2 = val_2, ..., то на выходе получим словарь с целевыми элементами {'key_name_1': val_1, 'key_name_2': val_2, ...}, в котором ключами будут строки с переданными именами, т.е. допустимыми в Python идентификаторами. Также можно передавать конструктору список с кортежами пар значений [(key_1, val_1), (key_2, val_2), ...], первое из которых станет ключом, а второе элементом словаря. Например, инструкции dict(one = 1, two = 2) и dict([('one', 1), ('two', 2)]) в обоих случаях вернут словарь {'one': 1, 'two': 2} (см. пример №3).

Код Результат pythonCodes
# Получаем пустой словарь.
dict_1 = dict()
# Выведет {}.
print(dict_1, end='\n\n')        

# Используем пары «идентификатор = значение».
dict_2 = dict(one = 1, two = 2)
# Выведет {'one': 1, 'two': 2}.
print(dict_2, end='\n\n')

# Используем список с кортежами пар.
dict_3 = dict([('one', 1), ('two', 2)])
# Выведет опять же {'one': 1, 'two': 2}.
print(dict_3, end='\n\n')       

# Разрешены любые допустимые ключи.
dict_4 = dict([(1, 'one'), (2, 'two')])
# Выведет {1: 'one', 2: 'two'}.
print(dict_4)
{}

{'one': 1, 'two': 2}

{'one': 1, 'two': 2}

{1: 'one', 2: 'two'}


 
 
 
 




		
			

Пример №3. Создание словарей в Python (часть 2).

Обратите внимание, что при передаче в конструктор пар «имя_ключа = значение» в качестве ключей используются допустимые в Python идентификаторы, а не строки. Поэтому их в кавычки брать не нужно. Во втором же варианте можно использовать любые допустимые ключи, т.е. не только строки, но и, например, числа или кортежи.

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

Код Результат pythonCodes
# Словарь с квадратами чисел 2, 3, 4.
d_1 = {x: x**2 for x in range(2,5)}
# Выведет {2: 4, 3: 9, 4: 16}.
print(d_1, end='\n\n')        

# Цикл с двумя переменными.
d_2 = {k: v for k,v in [('a', 1), ('b', 2)]}
# Выведет {'a': 1, 'b': 2}.
print(d_2, end='\n\n')

# Словарь с ключами и значением  по умолчанию.
d_3 = {k.lower(): None for k in 'ABC'}
# Выведет {'a': None, 'b': None, 'c': None}.
print(d_3)
{2: 4, 3: 9, 4: 16}

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

{'a': None, 'b': None, 'c': None}


 
 
 
 

		
			

Пример №4. Создание словарей в Python (часть 3).

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

Встроенная функция range(start, stop[, step]) в примере принимает в качестве аргументов целые числа от start до stop (не включая данный предел) с необязательным шагом step, а возвращает итератор с последовательностью чисел из заданного диапазона. Поскольку итератор представляет собой специальный объект, который возвращает свои элементы по одному за раз, а не все сразу, как кортежи или списки, это позволяет экономить оперативную память, в особенности, если элементов очень много. Если все таки нужен не итератор, а сразу список или кортеж, можно использовать соответствующий конструктор. Например, list(range(3)) вернет список [0, 1, 2], list(range(1, 3)) вернет список [1, 2], list(range(1, 7, 2)) вернет список [1, 3, 5], list(range(7, 2, -2)) вернет список [7, 5, 3] и т.д. Позже мы разберем эту функцию подробнее.

Но и это еще не все, для создания словарей в Python можно использовать специальный метод класса dict.fromkeys(iterable[, value]), который возвращает словарь, исполь­зующий в качестве своих ключей элементы итерируемого объекта iterable, а в качестве их значений второй необязательный параметр value, который по умолчанию принимается за None (см. пример №5).

Код Результат pythonCodes
# Словарь с 3-мя эл-ми со значением None.
d_1 = dict.fromkeys([1, 2, 3])
# Выведет {1: None, 2: None, 3: None}.
print(d_1, end='\n\n')        

# Указываем значение для ключей словаря.
d_2 = dict.fromkeys(range(1, 3), 'Ok')
# Выведет {1: 'Ok', 2: 'Ok'}.
print(d_2, end='\n\n') 		

# Используем для ключей символы строки.
d_3 = dict.fromkeys('abc', 0)
# Выведет {'a': 0, 'b': 0, 'c': 0}.
print(d_3, end='\n\n')
{1: None, 2: None, 3: None}

{1: 'Ok', 2: 'Ok'}

{'a': 0, 'b': 0, 'c': 0}


 
 
 
 

		
			

Пример №5. Создание словарей в Python (часть 4).

Ключи словаря в Python

В качестве ключей словаря в Python могут использоваться только объекты неизме­няемых типов данных, т.к. они позволяют однозначно идентифицировать элементы словаря. Сюда относятся числа, строки, кортежи с неизменяемыми элементами, фиксированные множества, None, логические значения и другие неизменяемые типы данных (см. пример №6).

Код Результат pythonCodes
# Импортируем числа типа Decimal.
from decimal import Decimal

# Используем для ключей строки.
dict_1 = {'num': 1, 'abc': 'Алфавит'}
print(dict_1, end='\n\n') 
		
# Используем для ключей числа.
dict_2 = {1: 'int', -0.2: 'float', 3j: 'complex'}
print(dict_2, end='\n\n') 						

# Используем числа типа Decimal.		
dict_5 = {Decimal(-0.5): 'Неизм. тип данных'}
print(dict_5, end='\n\n') 

# Используем логические значения и None.
dict_6 = {True: 0, False: 1, None: 'Не число'}
print(dict_6, end='\n\n') 		

# Кортежи с неизменяемыми элементами.
dict_7 = {(True, 'a'): 1, (-0.7, (None, 5j)): 3}
print(dict_7, end='\n\n') 		

# Создаем фиксированное множество из эл-тов списка.
fr_set = frozenset([-3.1, None, 'a'])
# Используем его в качестве ключа (некрасиво как-то).		
dict_8 = {fr_set: 'Неизм. объект'}
print(dict_8, end='\n\n') 
		
# Пробуем использовать список.		
dict_9 = {[1, 2]: 'Так нельзя!'}
# Получаем ошибку, т.к. списки изменяемы.		
print(dict_9)
{'num': 1, 'abc': 'Алфавит'}

{1: 'int', -0.2: 'float', 3j: 'complex'}

{Decimal('-0.5'): 'Неизм. тип данных'}

{True: 0, False: 1, None: 'Не число'}

{(True, 'a'): 1, (-0.7, (None, 5j)): 3}

{frozenset({None, 'a', -3.1}): 'Неизм. объект'}

unhashable type: 'list'


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

		
			

Пример №6. Примеры использования ключей словаря.

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

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

Код Результат pythonCodes
# Используем одинаковые ключи.
d_1 = {'ok': 'yes', 'ok': 'да'}
# У меня вывело да да.
print(d_1['ok'], d_1['ok'], end='\n\n')	

# Используем одновременно 1 и True.
d_2 = {1: 'один', True: 'one'}
# У меня вывело one one.
print(d_2[1], d_2[True], end='\n\n')

# Используем одновременно 0 и False.
d_3 = {0: 'ноль', False: 'zero'}
# У меня вывело zero zero.
print(d_3[0], d_3[False], end='\n\n')		

# Сохраняем объект в переменной.
s_ok = 'ok'
# Сохраняем в словаре под разными ключами.
d_3 = {'да': s_ok, 'yes': s_ok}
# Выведет ok, ok.
print(d_3['да'], d_3['yes'], sep=', ')
да да

one one

zero zero

ok, ok


 
 
 
  
 
 
 
 
 

		
			

Пример №7. Нюансы использования ключей словаря.

Не используйте в качестве ключей одновременно 0 и False (интерпретатор считает это значение нулем), а также 1 и True (интерпретатор считает его единицей). К этой особенности мы еще вернемся, когда будем рассматривать логический тип данных.

Доступ к элементам словаря в Python

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

Код Результат pythonCodes
# Формируем простой словарь.
d_1 = {1: 'один', 'yes': 'да'}
# Выведет один да.
print(d_1[1], d_1['yes'], end='\n\n')	

# Используем вложенные списки и словари.
d_1 = {'li': [{'ok': 1, 'no': 2}, 3], 's': 'abc'}
# Выведет 2 b.
print(d_1['li'][0]['no'], d_1['s'][1])
один да

2 b




		
			

Пример №8. Доступ к элементам словаря по ключу.

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

Что касается извлечения не одного, а сразу целого диапазона элементов, то для словарей такая операция не предусмотрена, т.к. словари являются неупоря­доченными коллекциями объектов.

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

Код Результат pythonCodes
# Формируем словарь.
d_1 = {1: 1, 2: 2, 3: 0.3}

# Изменяем значение элемента.		
d_1[3] = 3
# Выведет {1: 1, 2: 2, 3: 3}.		
print(d_1, end='\n\n')

# Добавляем новый эл-т.		
d_1[4] = 4
# Выведет {1: 1, 2: 2, 3: 3, 4: 4}.		
print(d_1)	
{1: 1, 2: 2, 3: 3}

{1: 1, 2: 2, 3: 3, 4: 4}







		
			

Пример №9. Изменение и добавление новых элементов в словарь.

Операторы словарей в Python

Поскольку словари относятся к неупорядоченным коллекциям объектов, операторы +, +=, * и *= с ними не используются.

Что касается оператора проверки на вхождение in, то примени­тельно к словарям он совершает поиск переданного ключа (левый операнд) среди ключей целевого словаря (правый операнд). В случае успеха операция возвращает True, иначе – False (см. пример №10).

Код Результат pythonCodes
# Формируем простой словарь.
d_1 = {1: 'один', 'yes': 'да'}
		
# Выведет True.
print(1 in d_1, end='\n\n')		
# Выведет False.
print('no' in d_1, end='\n\n')
# Выведет True.
print('no' not in d_1)
True

False

True


		
			

Пример №10. Использование оператора in применительно к словарям.

Применим к словарям и оператор цикла for, но словарь он обходит не по элементам, а по их ключам (см. пример №11).

Код Результат pythonCodes
# Формируем словарь.
d_1 = {1: 1, 2: 2, 3: 0.3}

# Запускаем цикл по ключам словаря.
for key in d_1:
	
    # Если эл-т не является целым числом,
    if not isinstance(d_1[key], int):
        # выводим на экран сообщение 
        print('Не все эл-ты словаря целые числа.')			
        # и прерываем цикл.
        break

# Eсли цикл завершился успешно,
else:
    # выводим положительный результат. 
    print('Все эл-ты в словаре - целые числа.')	
Не все эл-ты словаря целые числа.














		
			

Пример №11. Использование цикла for для обхода элементов словаря по ключам.

Поскольку словари относятся к изменяемым коллекциям объектов произвольного типа, их элементы мы можем как добавлять, так и удалять. Последнюю операцию довольно просто выполнять при помощи знакомого нам оператора удаления del (см. пример №12).

Код Результат pythonCodes
# Формируем исходный словарь.
d_1 = {1: 1, 2: 2, 3: 0.3, 4: 4}
# Выводим его на экран. 
print('Исходный словарь:', d_1, end='\n\n')			

# Удаляем эл-т. 
del d_1[4]
# Выведет {1: 1, 2: 2, 3: 0.3}. 
print('Итоговый словарь:', d_1, end='\n\n')	

# Запускаем цикл по ключам словаря.
for key in d_1:
	# Если эл-т не является целым числом,
	if not isinstance(d_1[key], int):
		# удаляем его и получаем ошибку. 
		del d_1[key]

# dictionary changed size during iteration. 
Исходный словарь: {1: 1, 2: 2, 3: 0.3, 4: 4}

Итоговый словарь: {1: 1, 2: 2, 3: 0.3}

dictionary changed size during iteration











		
			

Пример №12. Использование оператора del применительно к словарям.

Поскольку словари относятся к неупорядоченным коллекциям объектов, изменять их размер во время итерации нельзя, т.к. интерпретатор выдаст ошибку.

Функции и методы словарей в Python

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

  • dict.fromkeys(iterable[, value]) – cоздает словарь с ключами из последо­ватель­ности iterable и одинаковыми значениями value. Если значение value не указать, будет использовано значение по умолчанию None.
  • dict.get(key[, default]) – возвращает значение по ключу key. Если ключа в словаре не окажется, будет возвращено значение по умолчанию default. Если default не указать, будет возвращено None (см. пример №13).
  • dict.setdefault(key[, default]) – также возвращает значение элемента по ключу key, но если элемента с таким ключом не окажется, в словарь будет добавлен новый элемент со значением default. Если же значение default передано не будет, метод установит добавляемому элементу значение None и вернет его.
Код Результат pythonCodes
# Формируем словарь.
d_1 = {'a': 1, 'b': 2, 'c': 3}
print("d_1 ->", d_1, end='\n\n')

# Получаем значение d_1['b']. Выведет 2.		
print("d_1.get('b') ->", d_1.get('b'))
# Пробуем получить d_1['d']. Выведет None.		
print("d_1.get('d') ->", d_1.get('d'))
# Используем значение по умолчанию. Выведет 4.		
print("d_1.get('d', 4) ->", d_1.get('d', 4), end='\n\n')				
# Убеждаемся, что словарь не изменился. 
print(d_1, end='\n\n')					

# Получаем значение d_1['b'].
v_1 = d_1.setdefault('b')
# Выведет 2. 
print("d_1.setdefault('b') ->", v_1)

# Добавляем новый эл-т со значением 4.
v_2 = d_1.setdefault('d', 4)
# Выведет 4.
print("d_1.setdefault('d', 4) ->", v_2)		

# Добавляем еще один эл-т со значением None.
v_3 = d_1.setdefault('e')
# Выведет None.
print("d_1.setdefault('e') ->", v_3, end='\n\n')					

# Выводим итоговый словарь на экран. 
print(d_1)	
d_1 -> {'a': 1, 'b': 2, 'c': 3}

d_1.get('b') -> 2
d_1.get('d') -> None
d_1.get('d', 4) -> 4

{'a': 1, 'b': 2, 'c': 3}

d_1.setdefault('b') -> 2
d_1.setdefault('d', 4) -> 4
d_1.setdefault('e') -> None

{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': None}











	
	
	
		
	
			

Пример №13. Методы словарей (часть 1).

  • dict.keys() – возвращает представление всех ключей словаря (см. пример №14).
  • dict.values() – возвращает представление всех значений словаря (подробнее о представлениях мы поговорим в следующем пункте).
  • dict.items() – возвращает представление всех элементов словаря в виде кортежей с парами (key, value), где первые значения представляют собой ключи словаря, а вторые – соответствующие им значения.
Код Результат pythonCodes
# Формируем словарь.
d_1 = {'a': 1, 'b': 2, 'c': 3}
print("d_1 ->", d_1, end='\n\n')

# Выведет список ключей ['a', 'b', 'c'].		
print("d_1.keys() ->", list(d_1.keys()))
# Выведет список значений [1, 2, 3].		
print("d_1.values() ->", list(d_1.values()))
# Выведет список [('a', 1), ('b', 2), ('c', 3)].		
print("d_1.items() ->", list(d_1.items()))
d_1 -> {'a': 1, 'b': 2, 'c': 3}

d_1.keys() -> ['a', 'b', 'c']
d_1.values() -> [1, 2, 3]
d_1.items() -> [('a', 1), ('b', 2), ('c', 3)]

	
		
	
			

Пример №14. Методы словарей (часть 2).

  • dict.update([other]) – обновляет словарь, добавляя в него новые элементы или обновляя значения уже существующих, и возвращает None (см. пример №15). В качестве источника новых ключей и значений выступает аргумент other, который может быть:
    • другим словарем;
    • итерируемым объектом с кортежами пар [(key_1, value_1), (key_2, value_2), ...], где первое значение будет ключом будущего элемента, а второе – соответствующим значением;
    • обычным набором пар key_1=value_1, key_2=value_2, ... (здесь, как и при создании словарей, в качестве ключей должны передаваться допустимые имена идентификаторов, которые в кавычки брать не нужно).
  • dict.pop(key[, default]) – удаляет и возвращает элемент с ключом key. Если элемент с указанным ключом отсутствует, будет возвращено значение по умолчанию default или возбуждено исключение KeyError, если значение по умолчанию передано не будет.
  • dict.popitem() – удаляет из словаря последний добавленный элемент и возвращает его в виде кортежа (key, value). Для пустого словаря вызов метода вызывает исключение KeyError. Отметим, что удалять элементы в порядке «последний пришел ‒ первый ушел» (LIFO) метод начал с версии Python 3.7. Ранее удаление происходило хаотично. Метод можно использовать, например, для деструктивного обхода элементов словаря, используемого для создания или изменения элементов другого словаря.
Код Результат pythonCodes
# Формируем пустой словарь.
d_1 = {}

# Передаем список пар.		
d_1.update([('a', 1), ('b', 0.2)])
# Выведет {'a': 1, 'b': 0.2}.
print("d_1.update([('a', 1), ('b', 2)]) ->", d_1)
# Перечисляем пары через запятую.		
d_1.update(b=2, c=0.3)
# Выведет {'a': 1, 'b': 2, 'c': 0.3}.
print("d_1.update(c=3, d=4) ->", d_1)		
# Используем другой словарь.		
d_1.update({'c': 3, 'd': 4})
# Выведет {'a': 1, 'b': 2, 'c': 3, 'd': 4}.
print("d_1.update({'c': 3, 'd': 4}) ->", d_1, '\n')		

# Удаляем и выводим d_1['c'].		
print("d_1.pop('c') ->", d_1.pop('c'))
# Выведет 0, т.к. эл-т d_1['f'] не сущ-ет.		
print("d_1.pop('f', 0) ->", d_1.pop('f', 0), '\n')		

# Удаляем эл-ты, вставленные последними.		
print("d_1.popitem() ->", d_1.popitem())
print("d_1.popitem() ->", d_1.popitem())
d_1.update([('a', 1), ('b', 2)]) -> {'a': 1, 'b': 0.2}
d_1.update(c=3, d=4) -> {'a': 1, 'b': 2, 'c': 0.3}
d_1.update({'c': 3, 'd': 4}) -> {'a': 1, 'b': 2, 'c': 3, 'd': 4}

d_1.pop('c') -> 3
d_1.pop('f', 0) -> 0

d_1.popitem() -> ('d', 4)
d_1.popitem() -> ('b', 2)









	
	
	
		
	
			

Пример №15. Методы словарей (часть 3).

  • dict.copy() – возвращает поверхностную копию словаря (см. пример №16).
  • dict.clear() – удаляет все элементы из словаря и возвращает None.
Код Результат pythonCodes
# Формируем словарь.
d_1 = {'a': 1, 'b': [2, 3]}
# Выведет {'a': 1, 'b': [2, 3]}.
print("d_1 ->", d_1, end='\n\n')

# Создаем поверхностную копию словаря.
d_2 = d_1.copy()
# Выведет {'a': 1, 'b': [2, 3]}.
print("d_2 ->", d_2)	

# Очищаем словарь. Метод вернет None.
print("d_2.clear() ->", d_2.clear())
# Выведет пустой словарь {}.
print("d_2 ->", d_2)
d_1 -> {'a': 1, 'b': [2, 3]}

d_2 -> {'a': 1, 'b': [2, 3]}
d_2.clear() -> None
d_2 -> {}



	
	
	
		
	
			

Пример №16. Методы словарей (часть 4).

С методами словарей пока все. Теперь пройдемся по некоторым встроенным функциям, которые применимы к словарям. Остальные мы рассмотрим позже в процессе изучения материала по функциям.

  • len(dict) – возвращает количество элементов в словаре (см. пример №17).
  • list(dict) – возвращает список ключей словаря.
  • iter(dict) – возвращает итератор по ключам словаря. Метод является более короткой записью инструкции iter(dict.keys()). В отличие от представления dict.keys(), итератор является статичным набором ключей, который определяется состоянием словаря в момент вызова метода.
  • reversed(dict) – возвращает итератор по ключам словаря, но с выводом ключей в обратном порядке. Метод является более короткой записью инструкции reversed(dict.keys()).
Код Результат pythonCodes
# Формируем словарь.
d_1 = {'a': 1, 'b': 2, 'c': 3}

# Выведет 3.
print("len(d_1) ->", len(d_1))
# Выведет ['a', 'b', 'c'].
print("list(d_1) ->", list(d_1))		

# Преобразуем итератор в список для вывода.
li_iter = list(iter(d_1))
# Выведет ['a', 'b', 'c']. 
print("list(iter(d_1)) ->", li_iter)		

# Преобразуем «перевертыш» в список.
rvd_iter = list(reversed(d_1))		
# Выведет ['c', 'b', 'a'].
print("list(reversed(d_1)) ->", rvd_iter)
len(d_1) -> 3
list(d_1) -> ['a', 'b', 'c']
list(iter(d_1)) -> ['a', 'b', 'c']
list(reversed(d_1)) -> ['c', 'b', 'a']







	
	
	
		
	
			

Пример №17. Словари и встроенные функции.

Представления словарей в Python

Представления словарей – это еще одни специальные итерируемые объекты, которые обеспечивают динамическое представ­ление записей словаря. Это значит, что при изменении словаря (например, при удалении элемента) соответствующее представление будет автоматически изменяться, отражая эти изменения (см. пример №18).

Код Результат pythonCodes
# Формируем исходный словарь.
d_1 = {'a': 1, 'b': 2, 'c': 3}
# Выводим его на экран. 
print('Исходный словарь:', d_1, end='\n\n')			

# Сохраняем представления в переменных.
k = d_1.keys()
v = d_1.values()
i = d_1.items()
# Для примера получим один итератор.
ik = list(iter(d_1.keys()))
# Выводим их все на экран.
print(k, ik, v, i, '', sep='\n')
		
# Изменим словарь.
d_1['d'] = 4
del d_1['a']
# Выводим все на экран.
print(k, ik, v, i, sep='\n')
Исходный словарь: {'a': 1, 'b': 2, 'c': 3}

dict_keys(['a', 'b', 'c'])
['a', 'b', 'c']
dict_values([1, 2, 3])
dict_items([('a', 1), ('b', 2), ('c', 3)])

dict_keys(['b', 'c', 'd'])
['a', 'b', 'c']
dict_values([2, 3, 4])
dict_items([('b', 2), ('c', 3), ('d', 4)])






		
			

Пример №18. Автоматическое изменение представлений словаря.

Как видим, при изменении словаря его представления автоматически изменились. А вот итератор (преобразованный для наглядности в список) остался прежним.

Если по какой-то причине вместо представления тех же ключей словаря понадобится их список или кортеж, представление можно без проблем преобразовать с помощью соответствующего конструктора, например, list() или tuple(). Точно также, использовав встроенную функцию iter(), можно преобразовать представление в итератор.

Добавим, что для представлений также доступен ряд известных нам операций: функция len(), упомянутая только что функция iter(), метод reversed(), оператор проверки на вхождение in, а также обход посредством цикла for (см. пример №19).

Код Результат pythonCodes
# Формируем словарь.
d_1 = {'a': 1, 'b': 2, 'c': 3}
# Получаем представление ключей словаря.
k = d_1.keys()

# Выведет 3.
print("len(k) ->", len(k))
# Выведет False.
print("'d' in k ->", 'd' in k)		
# Выведет ['c', 'b', 'a'].
print("list(reversed(k)) ->", list(reversed(k)))

# Запускаем цикл по ключам словаря.
for key in k:		
    # Выводим на экран в одну строку.
    print(key, end=' ')
len(k) -> 3
'd' in k -> False
list(reversed(k)) -> ['c', 'b', 'a']
a b c 










		
			

Пример №19. Операции над представлениями словаря (часть 1).

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

Представления во многом похожи на множества, которые мы будем рассматривать в следующем параграфе. Поэтому в Python 3 для представления ключей dict.keys() и представления элементов dict.items() стали доступны операции, определенные для множеств set (см. пример №20).

Код Результат pythonCodes
# Формируем словари.
d_1 = {'a': 1, 'b': 2, 'c': 3}
d_2 = {'b': 2, 'c': 3, 'd': 4}

# Получаем представления ключей.
k_1 = d_1.keys()
k_2 = d_2.keys()

# Находим их пересечение.
k = k_1&k_2
# Получим {'c', 'b'}.
print("k_1&k_2 ->", k)		

# Объединяем представления.
k = k_1|k_2
# Получим {'a', 'd', 'b', 'c'}.
print("k_1|k_2 ->", k)

# Объединяем результат со множеством.
k = k|{'e', 'f'}
# {'d', 'c', 'a', 'e', 'b', 'f'}.
print("k|{'e', 'f'} ->", k)	
k_1&k_2 -> {'b', 'c'}
k_1|k_2 -> {'a', 'd', 'b', 'c'}
k|{'e', 'f'} -> {'d', 'c', 'a', 'e', 'b', 'f'}

















		
			

Пример №20. Операции над представлениями словаря (часть 2).

Что касается аналогичных операций в отношении представлений элементов словарей dict.items(), то здесь важно понимать, что они должны быть неизменяемыми, иначе интерпретатор вернет ошибку (см. пример №21).

Код Результат pythonCodes
# Формируем словари.
d_1 = {'a': 1, 'b': 2}
d_2 = {'b': 2, 'c': 3}
d_3 = {'a': [1, 2], 'b': 2}		

# Получаем представления эл-тов.
itm_1 = d_1.items()
itm_2 = d_2.items()
itm_3 = d_3.items()		

# Тут все нормально.
itm = itm_1&itm_2
# Получим {('b', 2)}.
print("itm_1&itm_2 ->", itm)		
# Узнаем тип рез-та (получим set).
print("type(itm) ->", type(itm))

# А здесь d_3[0] - изменяемый эл-т.
itm = itm_1&itm_3
# unhashable type: 'list'
print("itm_1&itm_3 ->", itm)
itm_1&itm_2 -> {('b', 2)}
type(itm) -> <class 'set'>
unhashable type: 'list'
















		
			

Пример №21. Операции над представлениями словаря (часть 3).

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

Краткие итоги параграфа

  • В Python словари представляют собой неупорядоченные изме­няемые коллек­ции объектов произвольного типа с доступом по ключу.
  • Чтобы создать словарь, нужно в фигурных скобках через запятую перечислить пары «ключ: значение», в которых ключи отделить от значений двоеточием (например, d = {'a': 1, 'b': 2}). В случае необходимости последний элемент словаря можно также завершить запятой. Это никак не повлияет на количество элементов словаря, а значит и его длину.
  • Кроме того, словари могут быть созданы при помощи конструктора dict(). Если использовать его без аргументов, то он вернет нам пустой словарь {}. Если передать конструктору через запятую пары key_name_1 = val_1, key_name_2 = val_2, ..., то на выходе получим словарь с целевыми элементами {'key_name_1': val_1, 'key_name_2': val_2, ...}, в котором ключами будут строки с переданными именами, т.е. допустимыми в Python идентификаторами. Также можно передавать конструктору список с кортежами пар значений [(key_1, val_1), (key_2, val_2), ...], первое из которых станет ключом, а второе элементом словаря. Например, инструкции dict(one = 1, two = 2) и dict([('one', 1), ('two', 2)]) в обоих случаях вернут словарь {'one': 1, 'two': 2}.
  • Опять же, для создания словарей в Python могут использоваться генераторы словарей, которые применяют выражение к каждому элементу передаваемых последовательностей и на основе их вычисления возвращают готовые словари с элементами. Например, генератор {x: y for x, y in [('one', 1), ('two', 2)]} вернет нам все тот же словарь {'one': 1, 'two': 2}.
  • Дополнительно для словарей доступен специальный метод класса dict.fromkeys(iterable[, value]), который возвращает словарь, исполь­зующий в качестве своих ключей элементы итерируемого объекта iterable, а в качестве их значений второй необязательный параметр value, который по умолчанию принимается за None. Например, инструкция dict.fromkeys('ab', 0) вернет словарь {'a': 0, 'b': 0}.
  • После того, как словарь будет создан, доступ к его элементам можно получать при помощи соответствующих ключей, которые нужно указывать в квадратных скобках после имени или литерала словаря. Например, для словаря d = {'one': 1, 'two': 2} инструкция d['two'] вернет 2.
  • Поскольку словари могут содержать объекты любого типа данных и любого уровня вложенности, цепочка доступа к конкретному элементу словаря может быть довольно длинной. Более того, она может включать не только квадратные скобки с ключами для доступа к элементам словарей, но и квадратные скобки с индексами для доступа к элементам списков, строк, кортежей или даже точки для доступа к атрибутам объектов. Например, для словаря d = {'a': [{'one': 1}, {'two': 2}], 'b': 2} инструкция d['a'][0]['one'] вернет 1.
  • В качестве ключей словаря в Python могут использоваться только объекты неизме­няемых типов данных, т.к. они позволяют однозначно идентифицировать элементы словаря. Сюда относятся числа, строки, кортежи с неизменяемыми элементами, фиксированные множества, None, логические значения True и False, а также другие неизменяемые типы данных. Примером словаря с ключами различных типов может служить словарь {3: 'int', -0.2: 'float', 3j: 'complex', (1, 2): 'tuple', False: 'bool', None: 'NoneType'}.
  • В словаре нельзя использовать один и тот же ключ для нескольких элементов. Ошибки интерпретатор не выдаст, но доступен будет только один из таких элементов. В то же время один и тот же объект вполне может быть доступен по разным ключам. Кроме того, не стоит использовать в качестве ключей одновременно 0 и False (интерпретатор считает это значение нулем), а также 1 и True (интерпретатор считает его единицей). Например, для словаря d = {0: 1, False: 2, 0: 3} инструкция d[0] вернет 3.
  • Поскольку словари являются изменяемыми коллекциями объектов, их можно изменять непосредственно: удалять элементы, добавлять новые, изменять значения уже существующих элементов. Например, пусть у нас есть словарь d = {'a': 1, 'b': 2}. Тогда инструкция d['c'] = None добавит в словарь новый элемент, d['c'] = 3 изменит значение добавленного элемента, а del d['a'] удалит из словаря элемент с указанным ключом.
  • Что касается операторов +, +=, * и *=, то они со словарями напрямую не используются. Однако к словарям применимы оператор in и цикл for. Первый проверяет наличие в словаре объекта с указанным ключом, а второй позволяет обойти все элементы словаря по их ключам.
  • Методы типа dict, как и методы списков, в основном изменяют словарь непосредственно, а не возвращают его измененную копию. Найти их можно в подразделе «Mapping Types — dict» раздела «Built-in types» стандартной библиотеки.
  • В конце параграфа мы познакомились с представлениями словарей – специальными итерируемыми объектами, которые обеспечивают динамическое представ­ление записей словаря. Это значит, что при изменении словаря соответствующее представление будет автоматически изменяться, отражая эти изменения. Например, получив один раз представление ключей словаря, мы в дальнейшем можем обращаться к нему за актуальной информацией о состоянии ключей даже после добавления в словарь новых или удаления уже существующих.

Вопросы и задания для самоконтроля

1. Какие из утверждений о словарях верны: упорядоченные, неупорядоченные, изменяемые, неизменяемые? Показать решение.

Ответ. Словари относятся к именованным изменяемым неупорядоченным коллекциям объектов.

2. Можно ли удалять элементы из словаря или добавлять в него новые? Почему? Показать решение.

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

3. Какие из представленых литералов относятся к типу dict: 5.0, {1: 'один', 2: 'два'}, [3, 4], "{'a': 1, 'b': 2}"? Проверьте типы программно. Показать решение.

Ответ. Тип dict: {1: 'один', 2: 'два'}.

Решение Результат pythonCodes
# Выводим типы представленных литералов.
print("Тип 5.0:", type(5.0))
print("Тип {1: 'один', 2: 'два'}:", type({1: 'один', 2: 'два'}))
print("Тип [3, 4]:", type([3, 4]))
print("Тип \"{'a': 1, 'b': 2}\":", type("{'a': 1, 'b': 2}"))
Тип 5.0: <class 'float'>
Тип {1: 'один', 2: 'два'}: <class 'dict'>
Тип [3, 4]: <class 'list'>
Тип "{'a': 1, 'b': 2}": <class 'str'>
			

4. Какие из представленых литералов могут быть использованы в качестве ключей словаря: 1.0, 'два', [3], (4, 'пять'), (6, [7], 'восемь'), 9, 10+3.0j, None? Почему? Проверьте свой ответ программно. Показать решение.

Ответ. Все, кроме [3] и (6, [7], 'восемь'), т.к. первый литерал относится к изменяемому типу, а во втором такой содержится.

Решение Результат pythonCodes
# Пробуем все ключи.
print({1.0: 'Да'})
print({'два': 'Да'})    
# unhashable type: 'list'
# print({[3]: 'Нет'})    
print({(4, 'пять'): 'Да'})    
# unhashable type: 'list'
# print({(6, [7], 'восемь'): 'Нет'})    
print({9: 'Да'})    
print({10+3.0j: 'Да'})
print({None: 'Да'})
{1.0: 'Да'}
{'два': 'Да'}
{(4, 'пять'): 'Да'}
{9: 'Да'}
{(10+3j): 'Да'}
{None: 'Да'}





5. Дан словарь d = {'a': [{'1': 'Ok!'}, 'No'], 'b': 3}. Как можно получить доступ к строке 'Ok!'? Показать решение.

Ответ. Необходимо использовать синтаксис доступа по индексам и ключам.

Решение Результат pythonCodes
# Сохраняем словарь в переменной.
d = {'a': [{'1': 'Ok!'}, 'No'], 'b': 3}
# Используем цепочку доступа по индексам и ключам.		
print(d['a'][0]['1'])
Ok!


			

6. Сколько элементов содержится в словаре d = {1: 'a', 2: ['ab', {'a': 1, 'b': 2}], (1, 2): ('a', 'b')}? А сколько в его элементе d[2]? Проверьте свои ответы программно. Показать решение.

Ответ. Словарь d содержит три элемента, а его элемент d[2] содержит два элемента.

Решение Результат pythonCodes
# Сохраняем словарь в переменной.
d = {1: 'a', 2: ['ab', {'a': 1, 'b': 2}], (1, 2): ('a', 'b')}
# Выводим кол-во эл-тов словаря.		
print("len(d) ->", len(d))			
# Выводим кол-во эл-тов d[2].		
print("len(d[2]) ->", len(d[2]))
len(d) -> 3
len(d[2]) -> 2



			

7. Изменится ли количество элементов в словаре d = {'a': 1, 'b': 1, 'c': 3}, если в нем поменять местами значения и ключи? Объясните ответ. Показать решение.

Ответ. После такой замены мы получим словарь с двумя элементами {1: 'b', 3: 'c'}. Дело в том, что ключи словаря должны быть уникальными, поэтому в ходе формирования целевого словаря каждый новый элемент будет перезаписывать значение уже существующего элемента с таким же ключом. Как осуществить такую замену программно, смотрите в нашем задачнике.

8. Перечислите три способа добавления нового элемента в словарь. Показать решение.

Решение Результат pythonCodes
# Целевой словарь.
d = {}  

# Добавляем по 1-му эл-ту.
d['1'] = 1
d.setdefault('2', 2)
d.update([('3', 3)])
        
# Выведет {'1': 1, '2': 2, '3': 3}.
print('d:', d)
d: {'1': 1, '2': 2, '3': 3}








			

9. Исправьте в коде все ошибки. Показать решение.

Условие pythonCodes
# Сохраняем словарь в переменной.
d = ('a': 1, 'b': 2, 'c': 3)		

# Добавляем в него новые элементы.
d.updait({1: 'one', 2: 'два'})			
# Удаляем элемент по ключу.
d.popitem('a')

# Ободим словарь по ключам.		
for k in d.items():
    # Выводим эл-т на экран.		
    print(d[k])
Условие Решение pythonCodes
# Сохраняем словарь в переменной.
d = ('a': 1, 'b': 2, 'c': 3)		

# Добавляем в него новые элементы.
d.updait({1: 'one', 2: 'два'})			
# Удаляем элемент по ключу.
d.popitem('a')

# Ободим словарь по ключам.		
for k in d.items():
    # Выводим эл-т на экран.		
    print(d[k])
# ('a': 1, 'b': 2, 'c': 3).
d = {'a': 1, 'b': 2, 'c': 3}		

# d.updait({1: 'one', 2: 'два'}).
d.update({1: 'one', 2: 'два'})			
# d.popitem('a').
d.pop('a')

# for k in d.items().		
for k in d.keys():
    # Выводим эл-т на экран.		
    print(d[k])

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

Ответ. dict.keys(), dict.values(), dict.items().

11. Дополнительные тесты по теме расположены в разделе «Словари» нашего сборника тестов.

12. Дополнительные упражнения и задачи по теме расположены в разделе «Словари» нашего сборника задач и упражнений.

Быстрый переход к другим страницам