Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 2 из 20 Начальный 15 мин 100 XP

Создание словаря: фигурные скобки и dict()

Три способа создать словарь: литерал в фигурных скобках, dict() из списка пар и пустой словарь под наполнение. Плюс разбор, какие ключи годятся и почему fromkeys с пустым списком — ловушка.

Редакция Питоники

Первый словарь уже получился: в уроке 1 телефонная книга собиралась фигурными скобками. Это главный способ — но не единственный. Разберём все: литерал в скобках, фабрику dict() и пустой словарь, который наполняется по ходу программы. Заодно выясним, какие значения можно ставить в роль ключа.

Литерал: фигурные скобки

Самый частый путь. Внутри фигурных скобок через запятую перечисляются пары, ключ отделяется от значения двоеточием. Функция len() считает пары — не ключи и не значения по отдельности:

литерал и len()
prices = {'молоко': 89, 'хлеб': 42}

print(prices)
print(len(prices))
Вывод
{'молоко': 89, 'хлеб': 42}
2

dict(): из списка пар и из другого словаря

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

dict() из списка пар
pairs = [('молоко', 89), ('хлеб', 42), ('сыр', 590)]
prices = dict(pairs)

print(prices)
print(len(prices))
Вывод
{'молоко': 89, 'хлеб': 42, 'сыр': 590}
3
копия и пары имя=значение
options = dict(theme='dark', lang='ru')
backup = dict({'молоко': 89, 'хлеб': 42})

print(options)
print(backup)
Вывод
{'theme': 'dark', 'lang': 'ru'}
{'молоко': 89, 'хлеб': 42}

Какие ключи годятся: строки и числа

Оговорка: имена при записи имя=значение подчиняются правилам имён переменных — латиница, без кавычек, поэтому русский ключ 'молоко' так не передать; для таких ключей остаётся литерал. Ключом же может быть любое неизменяемое значение: строка — самый частый выбор, число — второй (номера месяцев, коды ошибок, id записей). Строки и числа спокойно живут в одном словаре, а доступны каждый по-своему: строка — в кавычках, число — без. Как потом пополнять готовый словарь — урок 5.

строки и числа как ключи
calendar = {'год': 2026, 1: 'январь', 12: 'декабрь'}

print(calendar['год'])
print(calendar[1])
print(calendar[12])
Вывод
2026
январь
декабрь

Словарь из двух списков: zip

Отдельно стоит разобрать случай, который встречается на каждом втором собеседовании. Данные приходят двумя списками: один с названиями товаров, второй с ценами. dict() два списка не принимает — ждёт пары. Собирать их руками в цикле — работа, которая ломается при любой опечатке. Помогает встроенная функция zip: она берёт элементы списков попарно и отдаёт пары, а dict() превращает пары в словарь.

два списка — один словарь
names = ['молоко', 'хлеб', 'сыр']
prices = [89, 42, 590]

catalog = dict(zip(names, prices))

print(catalog)
print(catalog['сыр'])
Вывод
{'молоко': 89, 'хлеб': 42, 'сыр': 590}
590

Одна строка вместо цикла с присваиванием. Но есть подвох: zip останавливается на самом коротком списке. Если в названиях пять позиций, а в ценах четыре — пятая молча пропадёт, и словарь получится на пару короче, чем ожидала программа. Данные такой формы лучше проверять: сравните len(names) и len(prices) до сборки.

Пустой словарь и наполнение в цикле

Третий способ — создать пустой словарь и наполнять его по ходу. Это не экзотика: так работает почти любой код, который читает данные построчно. Сначала catalog = {}, потом в цикле catalog[name] = price. Преимущество в том, что не нужно знать заранее, сколько строк придёт, — словарь вырастет ровно настолько, насколько наполнят.

собираем каталог в цикле
catalog = {}
rows = [('молоко', 89), ('хлеб', 42), ('сыр', 590)]

for name, price in rows:
    catalog[name] = price

print(catalog)
print(len(catalog))
Вывод
{'молоко': 89, 'хлеб': 42, 'сыр': 590}
3

Здесь же живёт и первый настоящий сценарий ошибки: если два товара придут с одинаковым названием, второй молча перезапишет первый, и в каталоге окажется товаров меньше, чем строк в исходных данных. Мы на этом уже останавливались в уроке про добавление пар, но при чтении из внешнего источника забыть про это особенно легко.

fromkeys и общий список
base = dict.fromkeys(['молоко', 'хлеб', 'сыр'], [])

base['молоко'].append(89)
base['хлеб'].append(42)

print(base)
Вывод
{'молоко': [89, 42], 'хлеб': [89, 42], 'сыр': [89, 42]}

Один и тот же список под тремя ключами — вот что здесь получилось. Для неизменяемых значений, вроде нуля или пустой строки, fromkeys работает нормально: счётчик стартует с нуля у каждого ключа. Проблема ровно в изменяемых значениях.

dict(имя=значение) и когда он удобен

Третий вид вызова dict() принимает пары в виде именованных аргументов: dict(theme='dark', lang='ru'). Имена превращаются в строковые ключи. Ограничение видно сразу: имя аргумента обязано быть корректным идентификатором Python — латиница, без пробелов, без кириллицы. Русский ключ 'молоко' так не передать, для таких случаев остаётся литерал.

опции через именованные аргументы
options = dict(theme='dark', lang='ru', retries=3)

print(options)
print(len(options))
Вывод
{'theme': 'dark', 'lang': 'ru', 'retries': 3}
3

Зато читается такой код отлично — особенно когда это набор параметров по умолчанию: сразу видно, какие опции есть и какие у них значения. В реальных проектах такой словарь потом расширяют: options['timeout'] = 30. Поменять значение по ключу — одна строка, и все места, где опция читалась, сразу увидят новое.

Копия или оригинал

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

копия не связана с оригиналом
original = {'theme': 'dark', 'lang': 'ru'}
copy = dict(original)

copy['theme'] = 'light'

print(original)
print(copy)
print(original is copy)
Вывод
{'theme': 'dark', 'lang': 'ru'}
{'theme': 'light', 'lang': 'ru'}
False

Оригинал остался тёмным, копия — светлой, и is честно отвечает False: это два разных объекта. Правда, копия копирует только верхний уровень — вложенные словари и списки останутся общими. Про это — в уроке 19, там разбирают глубокие копии.

Словарь или список кортежей

Пара «ключ: значение» внутри списка — почти то же самое, только медленнее. Поиск по списку идёт перебором: чтобы найти цену молока в каталоге из 30 000 позиций, программа в среднем сравнит 15 000 кортежей. Словарь ищет иначе — он считает хеш ключа и сразу прыгает в нужную ячейку, поэтому ответ приходит независимо от размера каталога. На сотнях записей разницу не почувствуешь, она всплывает там, где записей тысячи.

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

поиск перебором и поиск по хешу
rows = [('молоко', 89), ('хлеб', 42), ('сыр', 590)]
prices = dict(rows)

def find_price(rows, key):
    for name, price in rows:
        if name == key:
            return price
    return None

print(find_price(rows, 'сыр'))
print(prices['сыр'])
Вывод
590
590

Что дальше

Словарь теперь можно создать тремя способами — литералом, через dict() и пустым с наполнением в цикле. Дальше самое интересное: что произойдёт, когда вы обратитесь к ключу, которого в словаре нет. В уроке 3 — настоящий traceback с KeyError и разбор того, как его читать, а в уроке 4 — мягкая замена через get.

Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

empty = {}
print(empty)
print(len(empty))
pairs = [('a', 1), ('b', 2)]
d = dict(pairs)
print(d)
d = {1: 'январь', '1': 'one'}
print(d[1])
print(d['1'])
Проверь себя
0 / 8

1. Как создать пустой словарь?

2. Что создаст запись {'а', 'б'} — с запятой, но без двоеточий?

3. Что вернёт len() для словаря из трёх пар?

4. Что сделает dict([('чай', 30), ('кофе', 120)])?

5. Какой ключ недопустим в словаре?

6. Как из двух списков names и prices собрать один словарь?

7. Что произойдёт, если длины names и prices различаются?

8. Почему dict.fromkeys(['a', 'b'], []) — ловушка?

Карточки терминов
Запомнено: 0 / 9
Практика

Дан список пар pairs = [('фильм', 8), ('сериал', 9)]. Преврати его в словарь ratings через dict() и выведи словарь, затем выведи, сколько в нём пар.

practice.py
Вопросы и ответы по уроку

Как создать словарь в Python?

Чаще всего литералом в фигурных скобках: prices = {'молоко': 89, 'хлеб': 42}. Пустой словарь — просто {}. Альтернатива — функция dict(): ей можно передать список пар dict([('чай', 30)]) или другой словарь, чтобы получить копию.

Урок 1: первый словарь

Чем {} отличается от dict()?

Результат одинаковый — пустой словарь. Но {} — это синтаксис литерала, а dict() — функция, которая к тому же умеет строить словарь из списка пар или копировать готовый словарь. В коде для пустого словаря обычно пишут {} — короче.

Можно ли сделать словарь из двух списков?

Напрямую dict() два списка не принимает: сначала собери из них список пар — zip(имена, значения) вернёт именно его, и dict(zip(names, prices)) соберёт словарь. А список пар (кортежей) dict() превращает в словарь напрямую, как показано в уроке.

Почему список нельзя сделать ключом словаря?

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

Как собрать словарь из двух списков одинаковой длины?

Через zip: dict(zip(names, prices)). zip берёт элементы списков попарно, а dict превращает пары в словарь. Важно помнить, что zip останавливается на самом коротком списке — если длины разошлись, лишние значения молча пропадут, без ошибки.

Урок 2: создание словаря

Что делает dict.fromkeys(['a', 'b'], [])?

Создаёт словарь, где у ключей 'a' и 'b' одно и то же значение — один и тот же объект списка. Изменение одного списка будет видно и в другом, потому что это не две копии, а одна. Для списков под каждым ключом нужен defaultdict(list).

Урок 12: defaultdict

dict(уже_существующий_словарь) — это копия?

Да, независимая копия верхнего уровня: изменения оригинала не видны в копии и наоборот. Но вложенные словари и списки копируются как ссылки — они останутся общими. Для глубокого копирования есть отдельный приём, разобранный в уроке 19.

Урок 19: сравнение словарей и копирование

Понравился урок? Сошлитесь на него

«Внутри фигурных скобок через запятую перечисляются пары, ключ отделяется от значения двоеточием.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.