Home› Tutorials› Standard Library
Standard LibraryThe collections Module: Specialised Containers Beyond list and dict
Counter(iterable)builds a frequency map in one line and supports addition, subtraction, andmost_common().defaultdict(factory)calls the factory to create a missing key's value instead of raisingKeyError.dequesupports O(1) append and pop from both ends; use it for queues and sliding windows.namedtuplecreates a tuple subclass with named fields, making index-based access obsolete.
What collections provides
Python's built-in list, dict, set, and tuple cover most everyday programming tasks. The collections module lives in the standard library and fills the gaps with specialised alternatives that are faster, more readable, or less error-prone for specific patterns.
| Class | Replaces / extends | Main use case |
|---|---|---|
Counter | dict | Frequency counting |
defaultdict | dict | Auto-initialise missing keys |
deque | list | Fast double-ended queue |
namedtuple | tuple | Lightweight named records |
OrderedDict | dict | Order-aware dict operations |
Import any class directly:
from collections import Counter, defaultdict, deque, namedtuple, OrderedDict
Counter: frequency counting
Counting how often each item appears in a sequence is a very common task. Without Counter you need a loop and an if guard. Counter does it in one call:
from collections import Counter
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
freq = Counter(words)
print(freq)
# Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(freq.most_common(2))
# [('apple', 3), ('banana', 2)]
Counter objects support arithmetic. Adding two counters merges their counts; subtracting removes counts (keeping only positive results):
a = Counter({"x": 4, "y": 2})
b = Counter({"x": 1, "y": 5, "z": 3})
print(a + b) # Counter({'y': 7, 'x': 5, 'z': 3})
print(a - b) # Counter({'x': 3}) # only positive results
Counter also works on strings, treating each character as an element.
defaultdict: automatic missing keys
A plain dict raises KeyError when you access a key that does not exist. defaultdict accepts a factory function and calls it to supply a default value the first time a missing key is accessed:
from collections import defaultdict
groups = defaultdict(list)
data = [("fruit", "apple"), ("veggie", "carrot"), ("fruit", "pear")]
for category, item in data:
groups[category].append(item)
print(dict(groups))
# {'fruit': ['apple', 'pear'], 'veggie': ['carrot']}
Common factories are list, set, int (defaults to 0), and str. You can also pass a lambda for any value:
dd = defaultdict(lambda: "unknown")
print(dd["missing_key"]) # "unknown"
deque: fast queue and stack
Python lists have O(1) append and pop at the right end, but O(n) insert and pop at the left end because every other element must shift. deque (double-ended queue) supports O(1) operations at both ends:
from collections import deque
q = deque([1, 2, 3])
q.appendleft(0) # O(1)
q.append(4) # O(1)
print(q) # deque([0, 1, 2, 3, 4])
q.popleft() # O(1) — removes 0
q.pop() # O(1) — removes 4
print(q) # deque([1, 2, 3])
Set a maxlen to create a sliding window that automatically discards the oldest entries:
recent = deque(maxlen=3)
for n in range(6):
recent.append(n)
print(recent) # deque([3, 4, 5], maxlen=3)
namedtuple: lightweight records
Ordinary tuples force you to remember what index 0, 1, and 2 mean. namedtuple creates a subclass of tuple with named fields. The result is immutable, memory-efficient, and self-documenting:
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 7)
print(p.x) # 3
print(p[0]) # 3 — index access still works
print(p) # Point(x=3, y=7)
Named tuples are fully compatible with tuple unpacking and work as dict keys (they are hashable). For mutable records with the same named-field syntax, see dataclasses.
OrderedDict: insertion-order dict
Since Python 3.7 plain dict preserves insertion order. OrderedDict still has two advantages: its move_to_end() method and the fact that its equality comparison takes order into account (two OrderedDict objects with the same pairs in different order are not equal):
from collections import OrderedDict
od = OrderedDict([("a", 1), ("b", 2), ("c", 3)])
od.move_to_end("a") # move "a" to the end
print(list(od.keys())) # ['b', 'c', 'a']
od.move_to_end("c", last=False) # move "c" to the front
print(list(od.keys())) # ['c', 'b', 'a']
OrderedDict is useful when implementing LRU caches or any algorithm where relative ordering of keys is semantically significant.
Choosing the right container
Use this decision guide:
- Need to count things? Use
Counter. - Building a dict of lists, sets, or totals without boilerplate guards? Use
defaultdict. - Need a queue or need to pop/append from both ends efficiently? Use
deque. - Returning a group of related values from a function and want readable field names? Use
namedtuple(ordataclassesif you need mutability). - Need order-sensitive dict equality or
move_to_end? UseOrderedDict.
All five are drop-in replacements for their built-in counterparts; switching requires only an import and a constructor change.