Словари
Теория
Словарь (dict) хранит пары ключ → значение: поле товара → его значение, id товара → товар, статус → число заказов. Значение достают не по номеру позиции, как в списке, а по ключу — и это очень быстро, сколько бы пар ни было в словаре. В backend словари повсюду: строка из базы, тело JSON-запроса, настройки, кэш — всё это словари или очень похожие на них структуры.
Ключи в словаре уникальны: запись по существующему ключу заменяет старое значение. Ключом может быть строка, число, кортеж — значение, которое не меняется (точное правило — в курсе «Python под капотом»); список ключом быть не может. Словарь изменяемый и с Python 3.7 сохраняет порядок добавления ключей. Чтобы обращение к отсутствующему ключу не роняло программу, есть метод get.
Наглядно
Таблица 1. Основные операции со словарём product = {"name": "Мышь", "price": 1499, "stock": 12}.
| Операция | Пример | Результат |
|---|---|---|
| значение по ключу | product["price"] |
1499; нет ключа — KeyError |
| безопасное чтение | product.get("color"), product.get("color", "не указан") |
None, "не указан" |
| добавить или заменить | product["stock"] = 11 |
ключ есть — замена, нет — добавление |
| удалить | product.pop("stock"), del product["stock"] |
pop возвращает значение |
| проверить ключ | "price" in product |
True — in проверяет ключи |
| число пар | len(product) |
3 |
| ключи, значения, пары | .keys(), .values(), .items() |
для перебора в цикле |
| объединить | product.update({"color": "black"}) |
добавит/заменит ключи из другого словаря |
На практике
Задача: описать товар словарём, собрать каталог {id: товар} и посчитать заказы по статусам.
Шаг 1. Создаём словарь
Товар — набор полей с именами, как строка таблицы products:
product = {"id": 42, "name": "Беспроводная мышь", "price": 1499, "stock": 12}
print(product["name"], product["price"])
print(len(product))Результат:
Беспроводная мышь 1499 4
Шаг 2. Читаем безопасно
У этого товара нет поля color. Квадратные скобки падают, get — нет:
print(product.get("color")) print(product.get("color", "не указан")) product["color"]
Результат:
None не указан KeyError: 'color'
get возвращает None или значение по умолчанию и не добавляет ключ в словарь.
Шаг 3. Добавляем и меняем значения
Запись по ключу заменяет значение, если ключ есть, и добавляет пару, если нет:
product["stock"] = 11 product["color"] = "black" print(product)
Результат:
{'id': 42, 'name': 'Беспроводная мышь', 'price': 1499, 'stock': 11, 'color': 'black'}Новый ключ встал в конец — словарь помнит порядок добавления.
Шаг 4. Удаляем значения
pop удаляет ключ и возвращает значение; второй аргумент — значение на случай, если ключа нет:
color = product.pop("color") discount = product.pop("discount", 0) print(color, discount) print("color" in product)
Результат:
black 0 False
Шаг 5. Проверяем наличие ключа
in для словаря проверяет ключи, а не значения:
print("stock" in product, 11 in product, 11 in product.values())
Результат:
True False True
Шаг 6. Обходим словарь
Цикл по словарю перебирает ключи; пары удобно брать через items() с распаковкой:
for key, value in product.items(): print(f"{key}: {value}")
Результат:
id: 42 name: Беспроводная мышь price: 1499 stock: 11
Шаг 7. Строим каталог
Каталог — словарь, где ключ — id товара, а значение — сам товар (тоже словарь):
catalog = {
42: {"name": "Беспроводная мышь", "price": 1499},
7: {"name": "Механическая клавиатура", "price": 5990},
}
print(catalog[7]["name"])
print(catalog.get(13))Результат:
Механическая клавиатура None
Поиск по id в словаре не перебирает товары — он сразу находит нужный, даже если товаров миллион.
Шаг 8. Считаем по ключам
Сколько заказов в каждом статусе. Для нового ключа берём 0 через get:
statuses = ["paid", "new", "paid", "cancelled", "paid"] counts = {} for status in statuses: counts[status] = counts.get(status, 0) + 1 print(counts)
Результат:
{'paid': 3, 'new': 1, 'cancelled': 1}Шаг 9. Не меняем размер словаря при обходе
Удалить отменённые статусы прямо в цикле по словарю нельзя:
for status in counts: if status == "cancelled": del counts[status]
Результат:
RuntimeError: dictionary changed size during iteration
Перебирайте копию ключей — for status in list(counts): — или соберите новый словарь.
Частые ошибки
d[key]для необязательного поля. Нет ключа —KeyError. Для полей, которых может не быть, —d.get(key, значение_по_умолчанию).counts[key] += 1для нового ключа. Ключа ещё нет —KeyError. Используйтеcounts.get(key, 0) + 1.- Ключ не того типа.
"42"и42— разные ключи:catalog["42"]не найдёт товар с ключом42. Данные из URL и форм — строки, их приводят к типу ключей. inпо значениям.11 in productпроверяет ключи. Для значений —11 in product.values().- Изменение размера при обходе. Добавление или удаление ключей в цикле по словарю —
RuntimeError.
Итог
Словарь
- Пары ключ → значение; поиск по ключу быстрый при любом размере.
- Ключи уникальны, неизменяемого типа (
str,int,tuple); порядок добавления сохраняется.
Чтение и запись
d[k]— значение илиKeyError;d.get(k, default)— без ошибки и без добавления ключа.d[k] = v— добавить или заменить;d.pop(k, default),del d[k]— удалить.k in d— проверка ключа.
Обход и подсчёт
for k in d,for k, v in d.items(),d.values().- Подсчёт:
counts[k] = counts.get(k, 0) + 1. - Не добавлять и не удалять ключи во время обхода.
Вопросы на собеседовании
Чем d[key] отличается от d.get(key)?
d[key] выбрасывает KeyError, если ключа нет. d.get(key) возвращает None (или переданное значение по умолчанию). Ни тот, ни другой не добавляют ключ в словарь.
Сохраняет ли словарь порядок элементов?
Да, с Python 3.7 порядок добавления ключей гарантирован спецификацией языка. Повторная запись по существующему ключу место не меняет. OrderedDict нужен только ради специфичных методов вроде move_to_end.
Что может быть ключом словаря?
Хешируемый объект: числа, строки, None, кортежи из хешируемых значений, frozenset. Списки, словари и множества — нет: они изменяемые, их хеш не постоянен.
Почему поиск по ключу в словаре быстрее, чем поиск в списке?
Словарь — хеш-таблица: по хешу ключа сразу вычисляется место, где лежит значение, — в среднем O(1). Список при поиске значения перебирает элементы по очереди — O(n).
Глубже
Как словарь находит ключ, что такое хеш и почему список не может быть ключом — в курсе «Python под капотом», темы «Hashable и неизменяемость» и «Как устроен dict».