Словари (dict) в языке Python: от основ до продвинутых техник

Раздел: Основы Python -> Типы данных и аннотации

Тип dict в Python: основы и варианты использования

Словарь (dict) - это изменяемая коллекция, хранящая пары «ключ-значение». Ключи должны быть хешируемыми (неизменяемыми), значения могут быть любого типа. Начиная с Python 3.7 словарь сохраняет порядок вставки элементов.

Создание словаря с помощью литерала {} - самый распространённый способ:


person = {
    "name": "Анна",
    "age": 30,
    "city": "Москва"
}
print(person)
  

Python type self (тип self в python)

{'name': 'Анна', 'age': 30, 'city': 'Москва'}
  

Python typing function (аннотация типа функции в python)

Возможные проблемы:

  • Попытка обратиться по отсутствующему ключу вызывает KeyError. Решение: использовать метод get() или проверку in.
  • Ключ должен быть хешируемым: нельзя использовать список или другой словарь. Для хранения нехешируемых ключей можно преобразовать их в кортеж.

Как создать словарь с помощью конструктора dict()?

Конструктор dict() позволяет создать словарь из последовательности пар (кортежей или списков) или из именованных аргументов:


# Из списка кортежей
items = [("a", 1), ("b", 2)]
d1 = dict(items)
print(d1)

# Из именованных аргументов
d2 = dict(name="Иван", age=25)
print(d2)
  

Python 3.12 type (новые возможности типов в python 3.12)

{'a': 1, 'b': 2}
{'name': 'Иван', 'age': 25}
  

Python typing type checking (проверка типов с помощью typing в python)

Цель:

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

Как применить словарное включение (dict comprehension)?

Словарное включение - генерация словаря на лету с помощью выражения {ключ: значение for элемент in последовательность}. Удобно для трансформации данных:


# Квадраты чисел от 1 до 5
squares = {x: x**2 for x in range(1, 6)}
print(squares)
  

Python type dict (тип dict в python)

{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
  

Python return type (тип возврата функции в python)

Типичная ошибка:

Попытка использовать изменяемый ключ (например, список) приведёт к ошибке TypeError: unhashable type.

Как создать словарь со значениями по умолчанию с помощью dict.fromkeys()?

Статический метод fromkeys(iterable, value) создаёт словарь, где каждый элемент из iterable становится ключом, а значение для всех ключей одинаково:


keys = ['a', 'b', 'c']
default_dict = dict.fromkeys(keys, 0)
print(default_dict)
  
{'a': 0, 'b': 0, 'c': 0}
  

Цель:

Быстрая инициализация словаря с фиксированным значением, например, для подсчёта или хранения настроек.

Как использовать defaultdict из модуля collections для автоматического создания значений?

defaultdict - подкласс dict, который при обращении к отсутствующему ключу автоматически создаёт запись со значением, возвращаемым фабричной функцией. Полезно для группировки или подсчёта:


from collections import defaultdict

# Счётчик букв в строке
text = "hello"
counter = defaultdict(int)
for ch in text:
    counter[ch] += 1
print(dict(counter))
  
{'h': 1, 'e': 1, 'l': 2, 'o': 1}
  

Проблема:

При сериализации (json.dumps) defaultdict превращается в обычный dict, но при десериализации не восстанавливается - требуется явное преобразование.

Как объединять два словаря с помощью оператора | и метода update?

Оператор | (Python 3.9+) и |= создают новый словарь, объединяя пары из обоих. Если ключи совпадают, приоритет у правого операнда:


d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
d3 = d1 | d2
print(d3)
  
{'a': 1, 'b': 3, 'c': 4}
  

Метод update() изменяет исходный словарь, добавляя пары из другого словаря или из итерабельной последовательности:


d1.update({'c': 5})
print(d1)
  
{'a': 1, 'b': 2, 'c': 5}
  

Как передавать словарь в функцию с помощью распаковки **?

Распаковка **dict позволяет передавать пары ключ-значение как именованные аргументы:


def greet(name, age):
    print(f"{name} is {age} years old")

info = {'name': 'Ольга', 'age': 28}
greet(**info)
  
Ольга is 28 years old
  

Цель:

Упрощает вызов функций с динамическими параметрами, считываемыми из конфигурации или пользовательского ввода.

Как указать аннотацию типа для словаря?

Для статической типизации используется Dict[KeyType, ValueType] из модуля typing:


from typing import Dict

# Пустой словарь с аннотацией
config: Dict[str, int] = {}

# Функция, возвращающая словарь
def get_scores() -> Dict[str, float]:
    return {'Alice': 95.5, 'Bob': 88.0}
  

В Python 3.9+ можно использовать встроенные dict[str, int]:


def process(data: dict[str, list[int]]) -> None:
    pass
  

Распространённые ошибки:

  • Изменение словаря во время итерации по его ключам может привести к непредсказуемому поведению. Решение: итерироваться по копии list(dict.keys()).
  • Неглубокое копирование (copy()) не копирует вложенные объекты. Для полного копирования используется copy.deepcopy().

Расширенные примеры использования словарей

Вложенные словари позволяют моделировать сложные структуры данных, например, базу пользователей:

Пример

users = {
    'user1': {
        'name': 'Екатерина',
        'age': 29,
        'roles': ['admin', 'editor']
    },
    'user2': {
        'name': 'Дмитрий',
        'age': 35,
        'roles': ['viewer']
    }
}
print(users['user1']['name'])  # Екатерина
Екатерина

Группировка элементов по ключу с использованием defaultdict - эффективное решение для обработки последовательностей:

Пример

from collections import defaultdict

words = ['apple', 'banana', 'apricot', 'blueberry', 'cherry']
grouped = defaultdict(list)
for word in words:
    first_letter = word[0]
    grouped[first_letter].append(word)
print(dict(grouped))
{'a': ['apple', 'apricot'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}

Использование словаря для кэширования результатов вычислительных функций (мемоизация):

Пример

def fib(n, cache={}):
    if n in cache:
        return cache[n]
    if n < 2:
        return n
    result = fib(n-1, cache) + fib(n-2, cache)
    cache[n] = result
    return result

print(fib(10))
print(fib(15))
55
610

Сериализация словаря в JSON и обратно:

Пример

import json

data = {'name': 'Тест', 'values': [1, 2, 3], 'nested': {'key': True}}
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
{
  "name": "Тест",
  "values": [1, 2, 3],
  "nested": {
    "key": true
  }
}

Обратное преобразование:

Пример

restored = json.loads(json_str)
print(restored == data)
True

Сортировка словаря по значению с получением списка ключей:

Пример

scores = {'Alice': 95, 'Bob': 82, 'Charlie': 91}
sorted_names = sorted(scores, key=lambda k: scores[k], reverse=True)
print(sorted_names)
['Alice', 'Charlie', 'Bob']

Слияние двух словарей с суммированием значений при совпадении ключей:

Пример

from collections import Counter

a = {'x': 10, 'y': 5}
b = {'x': 3, 'z': 7}
merged = Counter(a) + Counter(b)
print(dict(merged))
{'x': 13, 'y': 5, 'z': 7}

Удаление ключей с пустыми значениями из словаря:

Пример

raw = {'a': '', 'b': 0, 'c': None, 'd': 'hello'}
cleaned = {k: v for k, v in raw.items() if v}
print(cleaned)
{'d': 'hello'}

Преобразование списка пар в словарь с проверкой на дубликаты:

Пример

pairs = [('a', 1), ('b', 2), ('a', 3)]
result = {}
for k, v in pairs:
    if k in result:
        raise ValueError(f"Duplicate key: {k}")
    result[k] = v
print(result)
ValueError: Duplicate key: a

Тип dict в Python - comments

En
Python type dict (python)