collections в Python: defaultdict, Counter и deque — практическое руководство с примерами
Модуль collections в Python — это готовые структуры данных с оптимизированным поведением. В этой статье мы разберём три самых полезных инструмента: defaultdict, Counter и deque. Если вы ищете запрос вроде «collections в Python: defaultdict, Counter, deque», вы по адресу — ниже только практика и понятные примеры.
Когда использовать collections вместо list и dict
- Вы постоянно проверяете «есть ли ключ в словаре?» — вероятно, вам нужен defaultdict.
- Вы считаете частоты элементов (слова, статусы, клики) — это работа для Counter.
- Вам нужна очередь с быстрыми вставками/удалениями слева и справа — используйте deque.
defaultdict: словарь со значением по умолчанию
defaultdict автоматически создаёт значение для отсутствующего ключа. Это упрощает группировку и накопление данных.
from collections import defaultdict
names = ["Анна", "Андрей", "Борис", "Белла", "Гена"]
groups = defaultdict(list)
for name in names:
groups[name[0]].append(name)
print(dict(groups)) # {'А': ['Анна', 'Андрей'], 'Б': ['Борис', 'Белла'], 'Г': ['Гена']}
Типичный кейс — подсчёты без лишних проверок:
from collections import defaultdict
counts = defaultdict(int)
for word in "мир мир труд май труд".split():
counts[word] += 1
print(dict(counts)) # {'мир': 2, 'труд': 2, 'май': 1}
Полезные советы по defaultdict
- Выбирайте
default_factoryиз готовых типов:list,set,int,float— это безопасно и быстро. - Осторожнее с чтением несуществующих ключей: обращение
d[key]создаст ключ, что может «раздувать» словарь при чтении. - Перед сериализацией в JSON приводите к
dict:
import json
from collections import defaultdict
data = defaultdict(list, users=["ann"])
# json.dumps(data) # TypeError
print(json.dumps(dict(data))) # OK
Частые ошибки с defaultdict
# Ошибка: одна и та же ссылка на список для всех ключей!
bad_list = []
d = defaultdict(lambda: bad_list)
d['x'].append(1)
d['y'].append(2)
print(d) # оба ключа указывают на один и тот же список
# Правильно:
d = defaultdict(list)
Counter: частоты и топы за две строки
Counter — специальный словарь для подсчёта частот: слов, букв, статусов HTTP, событий и т.п.
from collections import Counter
text = "мир мир труд май труд"
c = Counter(text.split())
print(c) # Counter({'мир': 2, 'труд': 2, 'май': 1})
print(c.most_common(2)) # [('мир', 2), ('труд', 2)]
Обновление и операции над счётчиками:
c1 = Counter("aabbb")
c2 = Counter("bbcc")
print(c1 + c2) # Counter({'b': 5, 'a': 2, 'c': 2}) — поэлементная сумма
print(c1 - c2) # Counter({'a': 2, 'b': 1}) — только положительные разности
c = Counter()
c.update(["ok", "ok", "err"]) # {'ok': 2, 'err': 1}
c.update(["ok"]) # {'ok': 3, 'err': 1}
print(c.elements()) # итератор повторений по частоте
Подводные камни Counter
subtractможет сделать счётчики отрицательными. Очистить нули/минусы можно так:c += Counter()илиc = +c.most_commonвозвращает результаты в порядке убывания, но элементы с одинаковой частотой могут идти в любом порядке — не полагайтесь на стабильность для тай-брейков.
from collections import Counter
c = Counter(a=2, b=1)
c.subtract({'a': 3}) # a: -1
print(c) # Counter({'b': 1, 'a': -1})
print(+c) # Counter({'b': 1}) — убраны нули и отрицательные
deque: двусторонняя очередь для быстрых операций
deque обеспечивает амортизированную O(1) вставку и удаление с обоих концов. Идеально для очередей, слайдинговых окон и LRU-паттернов.
from collections import deque
dq = deque(maxlen=3)
for x in [1, 2, 3, 4]:
dq.append(x)
print(dq) # deque([2, 3, 4], maxlen=3)
dq.appendleft(0)
print(dq) # deque([0, 2, 3], maxlen=3)
dq.rotate(1)
print(dq) # deque([3, 0, 2], maxlen=3)
Скользящее среднее за окно фиксированного размера:
from collections import deque
def moving_avg(nums, k):
q, s = deque(), 0
for x in nums:
q.append(x); s += x
if len(q) > k:
s -= q.popleft()
if len(q) == k:
yield s / k
print(list(moving_avg([1, 2, 3, 4, 5], 3))) # [2.0, 3.0, 4.0]
Комбинированный пример: мини‑аналитика логов
Посчитаем частоты статусов, определим самый частый статус по каждому пути и сохраним последние N ошибок.
from collections import Counter, defaultdict, deque
logs = [
"200 /index", "404 /favicon.ico", "200 /api", "500 /api", "200 /index",
]
# 1) Частоты статусов
statuses = Counter(int(line.split()[0]) for line in logs)
print(statuses.most_common())
# 2) Самый частый статус по каждому пути
by_path = defaultdict(Counter)
for line in logs:
status, path = line.split()
by_path[path].update([int(status)])
print({p: c.most_common(1)[0] for p, c in by_path.items()})
# 3) Последние 2 ошибки
last_errors = deque(maxlen=2)
for line in logs:
if line.startswith(("4", "5")):
last_errors.append(line)
print(list(last_errors))
Лучшие практики и рекомендации
- Читабельность важнее трюков. Не превращайте простой код в «головоломку» только ради использования collections.
- API‑границы. Избегайте возврата
defaultdictнаружу — приводите кdict, чтобы не удивлять клиентов функции. - Производительность. Для подсчётов больших массивов строк
Counterиdefaultdict(int)работают заметно быстрее, чем «ручная» логика с проверками ключей. - deque с maxlen — простой способ сделать «буфер последних N событий» без лишнего кода и утечек памяти.
- Тесты. Для
most_commonс одинаковыми частотами не проверяйте порядок — сравнивайте множества или сортируйте вручную по второму критерию.
Частые вопросы и ошибки
- Почему
defaultdictсоздаёт ключ при чтении? Так устроен__missing__: обращениеd[key]создаёт значение. Для «безопасной» проверки используйтеkey in dилиd.get(key). - Почему
Counter.subtractделает отрицательные счётчики? Это ожидаемо: используйте+cилиc += Counter()для удаления нулей и отрицательных значений. - Когда лучше
defaultdict(list)вместо «если ключа нет — создай список»? Всегда, когда вы группируете элементы — код короче и быстрее.
Итоги
defaultdict, Counter и deque — фундаментальные инструменты модуля collections в Python. Они делают код короче, надёжнее и быстрее, если применять их по назначению. Освойте их — и многие повседневные задачи (подсчёты, группировки, очереди) будут решаться в пару строк.
Хотите системно прокачать Python и закрепить всё на проектах? Посмотрите программу и начните сегодня: Прокачать Python на практике — записаться на курс «Python с Нуля до Гуру» →
-
Создано 09.02.2026 17:01:37
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.