Python: уроки, справочник и задачи

Словари в Python на практике: от создания до копирования

Раздел: Словари в Python · Обновлено 31.10.2026

Работа со словарями в Python сводится к нескольким операциям: создать словарь, получить значение по ключу, добавить или удалить пару, перебрать содержимое. В статье каждая операция показана на коротком примере с результатом, рядом описаны частые ошибки: KeyError, изменение словаря во время цикла, поверхностная копия. В конце есть сводная таблица методов и ответы на типичные вопросы.

Словари в Python на практике: от создания до копирования
Фото: Moheen Reeyad / CC BY-SA 4.0, Wikimedia Commons
Содержание статьи
  1. Как устроен словарь и как его создать
  2. Получение значения по ключу
  3. Добавление, изменение и объединение
    1. Значение по умолчанию через setdefault()
  4. Удаление элементов
  5. Перебор словаря
  6. Генераторы словарей и вложенные структуры
    1. Копирование: copy() и deepcopy()
  7. Сводная таблица методов dict
  8. Частые вопросы
    1. Можно ли использовать список в качестве ключа?
    2. Как найти ключ по значению?
    3. Как получить ключ с максимальным значением?
    4. Чем d.keys() отличается от list(d)?

Как устроен словарь и как его создать

Словарь (тип dict) хранит пары ключ-значение и находит значение по ключу за постоянное время, независимо от размера. Ключом может быть только хешируемый объект: строка, число, кортеж из неизменяемых элементов, frozenset. Список или другой словарь ключом быть не могут, Python выбросит TypeError: unhashable type. Значения могут быть любыми, в том числе списками и вложенными словарями.

Начиная с Python 3.7 словарь гарантированно помнит порядок добавления ключей. Поэтому утверждение "словарь неупорядочен" из старых учебников уже неверно: при выводе и переборе пары идут в том порядке, в котором их добавили.

empty = {}
user = {"name": "Тимур", "age": 30}
same = dict(name="Тимур", age=30)          # ключи только строки
pairs = dict([("a", 1), ("b", 2)])         # из списка пар
zipped = dict(zip(["x", "y"], [10, 20]))     # из двух списков
marks = dict.fromkeys(["math", "physics"], 0)

print(zipped)  # {'x': 10, 'y': 20}
print(marks)   # {'math': 0, 'physics': 0}

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

Получение значения по ключу

Обращение через квадратные скобки возвращает значение или выбрасывает KeyError, если ключа нет. Метод get() в этой ситуации возвращает None или значение по умолчанию, переданное вторым аргументом. Проверить наличие ключа можно оператором in, он смотрит именно на ключи, а не на значения.

user = {"name": "Тимур", "age": 30}

print(user["name"])              # Тимур
print(user.get("city"))          # None
print(user.get("city", "нет"))   # нет
print("age" in user)             # True
print(30 in user)                # False, 30 это значение
print(30 in user.values())       # True

Скобки уместны, когда ключ обязан быть: отсутствие ключа тогда означает ошибку в данных, и лучше узнать о ней сразу. Метод get() подходит для необязательных полей, например при разборе JSON-ответа сервера.

Добавление, изменение и объединение

Присваивание d[key] = value создает новую пару или перезаписывает значение существующего ключа. Чтобы перенести сразу несколько пар, используют метод update() или операторы | и |=, которые появились в Python 3.9.

user = {"name": "Тимур", "age": 30}
user["age"] = 31                  # изменение
user["city"] = "Москва"           # добавление

extra = {"city": "Казань", "email": "t@example.com"}
merged = user | extra             # новый словарь, user не меняется
user.update(extra)                # меняет user на месте

print(merged["city"])  # Казань: при совпадении побеждает правый

Значение по умолчанию через setdefault()

Метод setdefault(key, default) возвращает значение ключа, а если ключа нет, сначала записывает в словарь default. Это удобно при группировке, когда для каждого ключа копится список.

words = ["кот", "кит", "дом", "дым", "сад"]
groups = {}
for w in words:
    groups.setdefault(w[0], []).append(w)

print(groups)  # {'к': ['кот', 'кит'], 'д': ['дом', 'дым'], 'с': ['сад']}

Ту же задачу решает collections.defaultdict(list): он создает пустой список при первом обращении к новому ключу, и код становится короче.

Удаление элементов

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

squares = {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
print(squares.pop(4))          # 16
print(squares.pop(10, None))   # None, без ошибки
print(squares.popitem())       # (5, 25)
del squares[1]
print(squares)                 # {2: 4, 3: 9}
squares.clear()
print(squares)                 # {}

Перебор словаря

Цикл for по словарю перебирает ключи. Для значений есть метод values(), для пар сразу с распаковкой метод items(). Все три метода возвращают представления (view): это не копии, а окна в живой словарь, они отражают последующие изменения.

prices = {"хлеб": 50, "молоко": 90, "сыр": 400}

for name, price in prices.items():
    print(f"{name}: {price} руб.")

total = sum(prices.values())
expensive = [k for k, v in prices.items() if v > 80]
print(total, expensive)  # 540 ['молоко', 'сыр']

Добавлять или удалять ключи прямо во время перебора нельзя, Python остановит цикл с ошибкой RuntimeError: dictionary changed size during iteration. Перебирайте копию списка ключей for k in list(d): или соберите новый словарь генератором. Для вывода по возрастанию значений пригодится сортировка словаря через sorted() с параметром key.

Генераторы словарей и вложенные структуры

Генератор словаря записывается в фигурных скобках через двоеточие и позволяет построить словарь из любой последовательности одной строкой, с фильтром if в конце.

squares = {x: x * x for x in range(1, 6)}
odd = {x: x * x for x in range(10) if x % 2}
inverted = {v: k for k, v in {"a": 1, "b": 2}.items()}

print(squares)   # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
print(odd)       # {1: 1, 3: 9, 5: 25, 7: 49, 9: 81}
print(inverted)  # {1: 'a', 2: 'b'}

Копирование: copy() и deepcopy()

Присваивание b = a не копирует словарь, обе переменные указывают на один объект. Метод copy() создает поверхностную копию: сам словарь новый, но вложенные списки и словари общие. Для полной независимости нужен copy.deepcopy().

import copy

config = {"db": {"host": "localhost"}, "debug": False}
shallow = config.copy()
deep = copy.deepcopy(config)

shallow["db"]["host"] = "10.0.0.1"
print(config["db"]["host"])  # 10.0.0.1, вложенный словарь общий
print(deep["db"]["host"])    # localhost

Сводная таблица методов dict

Полное описание каждого метода с примерами есть на странице про методы словаря и в официальной документации.

МетодЧто делаетВозвращает
get(k, d=None)Читает значение без ошибкиЗначение или d
setdefault(k, d=None)Читает, при отсутствии записывает dЗначение
update(other)Добавляет и перезаписывает парыNone
pop(k[, d])Удаляет пару по ключуЗначение
popitem()Удаляет последнюю добавленную паруКортеж (k, v)
keys(), values(), items()Дают представления ключей, значений, парОбъект view
copy()Поверхностная копияНовый dict
fromkeys(seq, v=None)Создает словарь из ключей с одним значениемНовый dict
clear()Удаляет все парыNone

Встроенные функции тоже работают со словарем: len(d) вернет число пар, sorted(d) отсортированный список ключей, min() и max() сравнивают ключи. Закрепить материал помогут задачи по словарям с решениями.

Частые вопросы

Здесь собраны вопросы, которые возникают у начинающих при работе с dict.

Можно ли использовать список в качестве ключа?

Нет, список изменяемый и не имеет хеша. Преобразуйте его в кортеж: d[tuple(my_list)] = value. Кортеж подойдет, только если внутри него тоже нет списков.

Как найти ключ по значению?

Прямого метода нет, нужен перебор: next((k for k, v in d.items() if v == target), None). Если поиск по значению нужен часто, держите второй, перевернутый словарь.

Как получить ключ с максимальным значением?

Передайте в max() метод get как функцию сравнения: max(d, key=d.get). Для минимального значения так же работает min().

Чем d.keys() отличается от list(d)?

d.keys() возвращает живое представление, которое меняется вместе со словарем и поддерживает операции множеств, например d1.keys() & d2.keys(). list(d) создает независимый список ключей на текущий момент.