Обзор
Модуль collections содержит специализированные контейнеры, дополняющие встроенные list, dict, set и tuple:
| Класс | Назначение |
|---|---|
deque | Двусторонняя очередь |
Counter | Подсчёт хешируемых объектов |
defaultdict | Словарь со значением по умолчанию |
OrderedDict | Словарь с операциями над порядком |
ChainMap | Объединённое представление нескольких словарей |
namedtuple | Кортеж с именованными полями |
UserDict, UserList, UserString | Базовые классы для расширения встроенных типов |
deque
Двусторонняя очередь с быстрыми операциями на обоих концах (O(1)):
from collections import dequed = deque([1, 2, 3])d.append(4)d.appendleft(0)print(d)print(d.pop())print(d.popleft())Методы deque
| Метод | Описание |
|---|---|
append(x), appendleft(x) | Добавление справа и слева |
pop(), popleft() | Извлечение справа и слева |
extend(iterable), extendleft(iterable) | Добавление нескольких элементов |
rotate(n) | Циклический сдвиг, положительное n — вправо |
clear() | Очистка |
copy() | Поверхностная копия |
count(x), index(x), insert(i, x), remove(x), reverse() | Как у списка |
maxlen | Максимальная длина или None |
d = deque([1, 2, 3, 4, 5])d.rotate(2)print(d)d.rotate(-1)print(d)Ограничение длины
При заданном maxlen старые элементы вытесняются:
last3 = deque(maxlen=3)for i in range(6): last3.append(i)print(last3)Результат: deque([3, 4, 5], maxlen=3).
Индексация в середине deque медленная — O(n). Для произвольного доступа используйте список.
Очередь для обхода в ширину
from collections import dequegraph = {"a": ["b", "c"], "b": ["d"], "c": ["d"], "d": []}def bfs(start): seen = {start} queue = deque([start]) order = [] while queue: node = queue.popleft() order.append(node) for nxt in graph[node]: if nxt not in seen: seen.add(nxt) queue.append(nxt) return orderprint(bfs("a"))Counter
Подкласс dict, считающий вхождения:
from collections import Counterc = Counter("abracadabra")print(c)print(c["a"])print(c["z"])print(c.most_common(2))print(list(c.elements())[:3])Методы Counter
| Метод | Описание |
|---|---|
most_common([n]) | Список пар (элемент, число) по убыванию |
elements() | Итератор элементов с повторами |
update(iterable_or_mapping) | Добавляет счётчики |
subtract(iterable_or_mapping) | Вычитает счётчики |
total() | Сумма счётчиков (Python 3.10+) |
Арифметика
a = Counter(x=3, y=1)b = Counter(x=1, y=2, z=4)print(a + b)print(a - b)print(a & b)print(a | b)Сложение и вычитание отбрасывают нулевые и отрицательные значения.
words = "the quick brown fox jumps over the lazy dog the end".split()print(Counter(words).most_common(1))defaultdict
Словарь, создающий значение при обращении к отсутствующему ключу:
from collections import defaultdictdd = defaultdict(list)dd["a"].append(1)dd["a"].append(2)dd["b"].append(3)print(dict(dd))counts = defaultdict(int)for ch in "hello": counts[ch] += 1print(dict(counts))tree = lambda: defaultdict(tree)root = tree()root["a"]["b"]["c"] = 1default_factory — вызываемый объект без аргументов: list, int, set, dict или любая функция. Проверка key in dd не создаёт ключ, а dd[key] создаёт.
OrderedDict
С Python 3.7 обычный dict сохраняет порядок, но OrderedDict по-прежнему имеет дополнительные возможности:
from collections import OrderedDictod = OrderedDict([("a", 1), ("b", 2), ("c", 3)])od.move_to_end("a")print(list(od))od.move_to_end("c", last=False)print(list(od))print(od.popitem(last=False))| Метод | Описание |
|---|---|
move_to_end(key, last=True) | Перемещает ключ в конец или начало |
popitem(last=True) | Удаляет с конца или начала |
Сравнение двух OrderedDict учитывает порядок, а обычных словарей — нет.
LRU-кеш
from collections import OrderedDictclass LRU: def __init__(self, capacity): self.capacity = capacity self.data = OrderedDict() def get(self, key): if key not in self.data: return None self.data.move_to_end(key) return self.data[key] def put(self, key, value): self.data[key] = value self.data.move_to_end(key) if len(self.data) > self.capacity: self.data.popitem(last=False)ChainMap
Объединяет несколько словарей в одно представление без копирования. Поиск идёт слева направо:
from collections import ChainMapdefaults = {"color": "red", "user": "guest"}env = {"user": "admin"}cli = {"color": "blue"}settings = ChainMap(cli, env, defaults)print(settings["color"])print(settings["user"])settings["new"] = 1print(cli)child = settings.new_child({"debug": True})print(child["debug"], child["color"])print(settings.maps)Запись и удаление затрагивают только первый словарь.
namedtuple
from collections import namedtuplePoint = namedtuple("Point", "x y")Person = namedtuple("Person", ["name", "age"], defaults=[0])p = Point(1, 2)print(p, p.x, p._asdict())print(Person("Anna"))Подробнее — в главе про tuple.
UserDict, UserList, UserString
Обёртки для безопасного наследования. Прямое наследование от dict или list часто не работает так, как ожидается, потому что встроенные методы не вызывают переопределённые:
class BadDict(dict): def __setitem__(self, key, value): super().__setitem__(key, value * 2)bad = BadDict(a=1)bad.update(b=2)print(bad)Результат: {'a': 2, 'b': 2} — update обошёл переопределённый метод. С UserDict он будет вызван:
from collections import UserDictclass GoodDict(UserDict): def __setitem__(self, key, value): super().__setitem__(key, value * 2)good = GoodDict(a=1)good.update(b=2)print(good)Результат: {'a': 2, 'b': 4}.
Абстрактные базовые классы
collections.abc содержит ABC для проверки интерфейсов:
| Класс | Требуемые методы |
|---|---|
Iterable | __iter__ |
Iterator | __iter__, __next__ |
Sized | __len__ |
Container | __contains__ |
Collection | __len__, __iter__, __contains__ |
Sequence | __getitem__, __len__ |
MutableSequence | плюс __setitem__, __delitem__, insert |
Mapping | __getitem__, __iter__, __len__ |
MutableMapping | плюс __setitem__, __delitem__ |
Set, MutableSet | операции множеств |
Callable | __call__ |
Hashable | __hash__ |
Generator, Awaitable, Coroutine | Протоколы генераторов и корутин |
from collections.abc import Iterable, Mapping, Sequenceprint(isinstance([1], Sequence))print(isinstance({}, Mapping))print(isinstance("abc", Iterable))print(isinstance({1}, Sequence))Задания
- Реализуйте скользящее среднее по последним
nзначениям черезdeque(maxlen=n). - Найдите топ-5 самых частых слов в тексте через
Counter. - Постройте настройки приложения из трёх уровней приоритета с помощью
ChainMap.
