Словарь в Python: ключ и значение
Словарь — структура «ключ — значение»: достаём номер телефона по имени из телефонной книги, сравниваем dict со списком на живых данных и заглядываем под капот — как Python находит значение по ключу.
Редакция Питоники
До сих пор данные жили в списках: элементы лежат по порядку, и достают их по номеру. Но у многих вещей из жизни номера нет — есть имя. Номер телефона ищут по имени человека, цену товара — по названию, перевод слова — по самому слову. Для таких пар «имя — данные» в Python есть словарь: dict. В этом первом уроке раздела создаём телефонную книгу и учимся доставать из неё значения.
Первый словарь: телефонная книга
Словарь — это набор пар: ключ и значение. Ключ — то, по чему ищем; значение — то, что находим. В телефонной книге ключ — имя, значение — номер. Пары перечисляются в фигурных скобках через запятую, ключ отделяется от значения двоеточием:
phone = {
'Анна': '+7 900 111-22-33',
'Борис': '+7 900 222-33-44',
'Вера': '+7 900 333-44-55',
}
print(phone)
print(phone['Борис'])
{'Анна': '+7 900 111-22-33', 'Борис': '+7 900 222-33-44', 'Вера': '+7 900 333-44-55'}
+7 900 222-33-44Разбираем. phone — словарь из трёх пар. Запись phone['Борис'] читается «значение из phone под ключом Борис»: в квадратных скобках стоит ключ, а не номер. Кавычки нужны, потому что ключ здесь — строка, имя человека. Найденное значение можно сразу использовать — печатать, складывать, сравнивать (а что будет, если ключа нет — отдельная история, ей посвящён урок про KeyError).
prices = {'молоко': 89, 'хлеб': 42, 'сыр': 590}
total = prices['молоко'] + prices['хлеб']
print(total)
print(prices['сыр'] > 500)
131 True
dict против списка: имя против номера
goods_list = ['молоко', 'хлеб', 'сыр']
print(goods_list[0])
goods = {'молоко': 89, 'хлеб': 42, 'сыр': 590}
print(goods['сыр'])
молоко 590
Список и словарь решают одну задачу — хранят набор значений, — но ищут по-разному: список отвечает на вопрос «что лежит на позиции 0?», словарь — «сколько стоит сыр?». У списка goods_list нулевая позиция занята молоком — но стоит переставить товары, и goods_list[0] вернёт уже другое. Словарь от порядка не зависит: ключ 'сыр' — это имя, а не позиция. Ключ — это имя, по которому лежит значение, а значение — то, что под этим именем хранится.
| Список | Словарь |
|---|---|
| Элемент достаётся по номеру: goods_list[0] | Элемент достаётся по имени: goods['сыр'] |
| Номер — позиция, её надо помнить и беречь от перестановок | Ключ — смысл: имя, название, id — его легко вспомнить |
| Годится для упорядоченного: шаги, дни, очередь | Годится для справочников: цены, настройки, контакты |
- настройки программы:
{'theme': 'dark', 'lang': 'ru'}— ключ задаёт, что настраиваем, значение — как; - данные из внешнего мира: JSON-ответы API по сути и есть словари — об этом раздел про json;
- подсчёты: ключ — слово, значение — сколько раз оно встретилось.
Ключ и значение: несимметричная пара
Слово «пара» обманчиво: ключ и значение ведут себя совсем по-разному. Ключ уникален — двух пар с одинаковым ключом в словаре не бывает. Значение, наоборот, повторяться может сколько угодно раз: два товара могут стоить одинаково, и это ничего не ломает. Ещё одно различие: ключ обязан оставаться неизменным всё время жизни словаря, а значение можно менять хоть каждую минуту. Именно поэтому словарь отлично работает там, где список уже не справляется: номер телефона у человека может совпасть с чьим-то ещё, но один человек не может занимать два места в телефонной книге.
stock = {
'молоко': 12,
'сыр': 12,
'хлеб': 5,
}
print(stock['молоко'])
print(stock['сыр'])
print(len(stock))
12 12 3
Значения совпадают, а пара всё равно одна на каждого товара — длина словаря равна трём. Ещё один нюанс, на котором спотыкаются даже опытные: ключи 1 и True для Python — один и тот же ключ, потому что True равно 1. Проверим.
d = {True: 'да', 1: 'одна'}
print(d)
print(len(d))
print(d[True])
{True: 'одна'}
1
однаВ словаре осталась одна пара: при добавлении 1 значение 'да' было перезаписано на 'одна'. Никакой ошибки, никакого предупреждения. Про такие совпадения подробнее — в уроке про ключи.
Под капотом: как Python находит значение по ключу
Словарь устроен как хеш-таблица. Для каждого ключа Python вычисляет число — хеш, — и по остатку от деления на размер внутренней таблицы решает, в какую «ячейку» положить пару. При поиске по ключу хеш считается заново, и Python идёт сразу в нужную ячейку, а не перебирает все пары подряд. Отсюда то самое ощущение мгновенности: на словаре из трёх пар и на словаре из трёх миллионов поиск занимает примерно одинаковое время. Плата за это — память: словарь хранит ещё и хеши, и служебные записи о занятости ячеек, поэтому на одинаковых данных он заметно тяжелее списка.
print(hash('молоко') == hash('молоко'))
print(hash(1) == hash(1.0))
print(hash('молоко') == hash('хлеб'))
True True False
Один и тот же ключ всегда даёт один и тот же хеш — на этом и держится вся адресация. Но хеши разных ключей вполне могут совпасть: hash('молоко') и hash('хлеб') в примере разные, а для других строк бывает и одинаково. Словарь в таком случае не сломается, а просто разложит обе пары по соседним ячейкам и при поиске проверит их лишний раз. Именно поэтому говорят, что словарь даёт «почти» постоянное время, а не абсолютно постоянное.
stock = {}
stock[[1, 2]] = 'список в ключе'
Traceback (most recent call last):
File "example.py", line 2, in <module>
stock[[1, 2]] = 'список в ключе'
~~~~~^^^^^^^^
TypeError: unhashable type: 'list'Сценарий: прайс, который меняется каждый день
Возьмём задачу, где список ломается буквально на второй день работы. Есть прайс: хлеб — 42, молоко — 89, сыр — 590. Списком это выглядит так: ['хлеб', 'молоко', 'сыр'] и отдельно [42, 89, 590]. В первый день работает. На второй приходит заказ «молоко, две штуки», и программист дописывает новый товар в конец — потому что дописать в середину списка значит сдвинуть все последующие индексы. Через неделю в прайсе двадцать позиций, цена молока поехала, а счёт выставляется не на ту сумму. Найти, где ошибка, невозможно: индексы-то правильные, просто относятся к другим товарам.
Со словарём эта ошибка невозможна в принципе. Цена лежит рядом с названием, и названия не меняют свою цену при добавлении нового товара: prices['молоко'] всегда вернёт 89, пока это значение не перезапишут явно. Мы в редакции так и делали — перевели прайс на словарь и больше к индексам не возвращались. Мой практический совет: если в структуре данных есть хотя бы одно «имя» — берите словарь, даже если элементов двадцать. А если это просто очередь шагов или дни недели — оставляйте список, там позиция и правда важна.
prices = {'хлеб': 42, 'молоко': 89, 'сыр': 590}
total = prices['хлеб'] + prices['молоко']
print(total)
prices['молоко'] = 95
print(prices['молоко'])
print(len(prices))
131 95 3
Что дальше
Первый словарь собран и прочитан. Дальше — как создавать словари разными способами и какие значения вообще можно поставить в ключ: в уроке 2 разбираем литерал, функцию dict() и пустой словарь под будущие пары. А если хочется сразу понять, что будет, когда ключа в словаре не окажется, — в уроке 3 разбираем KeyError и то, как его читать.
Сначала предскажи ответ в голове — это главный навык программиста.
book = {'кот': 'мяу', 'гусь': 'га'}
print(book['гусь'])
prices = {'чай': 50, 'кофе': 120}
print(prices['кофе'] - prices['чай'])
d = {'a': 1, 'b': 2}
print(d['b'])
print(d['a'] + d['b'])
1. Что такое словарь в Python?
2. В словаре phone = {'Анна': '111'} — как достать номер Анны?
3. Чем словарь принципиально отличается от списка?
4. Что напечатает print(phone) для словаря из трёх пар?
5. Почему запись phone[Анна] без кавычек — ошибка?
6. Что произойдёт, если попробовать использовать список как ключ словаря?
7. Почему поиск по ключу в словаре работает быстро даже при миллионе пар?
8. Словарь d = {True: 'да', 1: 'одна'}. Сколько пар в нём и что под ключом True?
Собери словарь prices с тремя парами: молоко — 89, хлеб — 42, сыр — 590. Выведи словарь целиком, затем достань цену сыра по ключу и выведи её.
Что такое словарь в Python простыми словами?
Это контейнер, который хранит пары «ключ — значение» и находит значение по ключу. Как телефонная книга: имя — ключ, номер — значение. Записывается фигурными скобками, а значение достаётся записью вида phone['Анна'].
Урок 2: создание словаряЧем словарь отличается от списка?
Список ищет по номеру позиции: goods[0] — «что лежит первым». Словарь ищет по имени: goods['сыр'] — «сколько стоит сыр». Поэтому при перестановке элементов список даёт уже другие данные по старым индексам, а словарь находит значение по ключу независимо от порядка пар.
Как получить значение из словаря по ключу?
Записать ключ в квадратных скобках: phone['Борис']. Ключ-строка — в кавычках, число — без. Если ключа в словаре нет, такая запись упадёт с KeyError — как читать без падений, разобрано в уроке про метод get.
Урок 4: метод getМожет ли ключ быть числом?
Да: словарь {1: 'январь', 2: 'февраль'} корректен, доступ — по числу без кавычек: months[1]. Ключом годится любое неизменяемое значение; чаще всего берут строки и числа. Полный разбор — в уроке про создание словарей.
Почему список нельзя использовать как ключ словаря?
Словарь находит значение по хешу ключа, а хеш считается заранее и хранится внутри неизменяемого значения. Список изменяемый — его хеш изменился бы, и словарь перестал бы находить пару. Python запрещает такое на уровне типа: TypeError: unhashable type: 'list'. Годятся строки, числа и кортежи из неизменяемых элементов.
Урок 18: ключи — что можно и что нельзяЧем словарь лучше списка на практике?
Словарь привязывает значение к имени, а не к позиции. Добавление нового товара в середину списка сдвигает все последующие индексы, и цена одного товара молча начинает соответствовать другому. Со словарём такого не происходит: prices['молоко'] вернёт своё значение независимо от того, сколько позиций добавилось. Если в данных есть хоть одно имя — берите словарь.
Что произойдёт, если в словаре встретятся True и 1?
Для Python это один и тот же ключ: True равно 1, поэтому вторая пара перезапишет первую, а длина словаря будет 1. Ни ошибки, ни предупреждения. Такие совпадения редки в прикладном коде, но в задачах с флагами и счётчиками попадаются — проверяйте, не смешиваете ли вы типы ключей.
Понравился урок? Сошлитесь на него
«Ключ — это имя, по которому лежит значение, а значение — то, что под этим именем хранится.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Словари · Урок 2
Создание словаря: фигурные скобки и dict()
Три способа создать словарь: литерал в фигурных скобках, dict() из списка пар и пустой словарь под наполнение. Плюс разбор, какие ключи годятся и почему fromkeys с пустым списком — ловушка.
Словари · Урок 3
Доступ по ключу и KeyError
Что происходит при доступе по несуществующему ключу: настоящий traceback, построчный разбор KeyError, отлов через try/except и случаи, когда падение — правильное поведение.
Словари · Урок 7
in: проверка ключа в словаре
Оператор in отвечает на вопрос «есть ли такой ключ»: проверка перед доступом вместо KeyError, not in, грабли с проверкой значений и причина скорости поиска.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Исключения · Урок 11
KeyError в Python: ошибки словарей
Словарь не нашёл ключ — и честно сказал об этим KeyError. Разбираем объект ошибки, читаем из него ключ и выбираем между get, in и честным исключением.
keyerror словарь pythonpython словарь нет ключа
json · Урок 8
Путь к значению: достаём данные из глубины
Цепочки data["user"]["name"] и data["items"][0]["price"], KeyError у отсутствующих полей и get с умолчанием — спуск по типичному ответу API без падений.
python достать значение из jsondict get python умолчание
Словари · Урок 10
setdefault: значение при первом обращении
setdefault возвращает значение по ключу, а если ключа нет — сначала записывает умолчание: группировка гостей по городам без if-проверок, счётчики и подводный камень с вычислением аргумента.
setdefault словарь pythonгруппировка словарь python