Python Collections Module: Counter, defaultdict, deque and namedtuple with Worked Examples

Counter counts values, defaultdict creates missing groups, deque works at both ends, and namedtuple gives fixed records readable fields.

KnowledgeGate Team

Exam prep & CS education

Updated 7 Nov 20265 min read
Python Collections Module: Counter, defaultdict, deque and namedtuple with Worked Examples

You already know list, tuple and dict, but manual counting, grouping and queue code can still make a simple program noisy. Specialised collections containers reduce that boilerplate. Their edge cases include missing keys, non-positive counts, bounded eviction and immutable records, so they complement the built-ins rather than replace them.

For built-in str, list, tuple, set and dict, plus a worked word counter, use Python Collections and Strings: Complete Guide with a Worked Word Counter. Python programming course connects collections to file paths, CSV, dates, statistics and JSON. The collections module itself handles narrower container jobs: counting, missing-key factories, two-ended queues, named records, layered mappings and explicit reordering.

Python collections module: choose the container from the operation

The collections module packages containers for recurring data-structure operations. Import names explicitly so each dependency and container choice remains visible:

python
from collections import Counter, defaultdict, deque, namedtuple, ChainMap, OrderedDict

Avoid from collections import *. Explicit imports make both intent and dependencies clearer.

Operation you need

Container

Count frequencies

Counter

Initialise missing keys or group values

defaultdict

Add or remove items at either end

deque

Create a lightweight named record

namedtuple

Search layered mappings

ChainMap

Reorder keys explicitly

OrderedDict

UserDict, UserList and UserString wrap built-in container behaviour for subclasses that need controlled overrides. Use them when a custom container benefits from delegation to an underlying data object. These wrapper bases connect Python syntax to practical Coding & DSA work.

Counter in Python: count, query, update and subtract

Counter counts hashable values and returns zero for a missing item:

python
orders = ["pen", "book", "pen", "pencil", "book", "pen", "eraser"]
counts = Counter(orders)

print(dict(counts))        # {'pen': 3, 'book': 2, 'pencil': 1, 'eraser': 1}

counts["pen"]             # 3
counts["marker"]          # 0
counts.most_common(2)     # [('pen', 3), ('book', 2)]

Now subtract stock adjustments from the same object:

python
counts.subtract({"pen": 1, "book": 2, "eraser": 2})
print(dict(counts))        # {'pen': 2, 'book': 0, 'pencil': 1, 'eraser': -1}
print(+counts)             # Counter({'pen': 2, 'pencil': 1})

Subtraction retains zero and negative counts. Unary plus creates a new Counter containing only positive counts. Counter keys use normal dictionary hashing, and a missing key still reads as zero.

Three-panel Counter chart shows counts before and after subtraction, then the positive counts retained by unary plus.

defaultdict in Python: group values without repeated key checks

With a plain dictionary, packages[city].append(tracking_id) raises KeyError when city is new. A defaultdict calls its factory to create the missing list:

python
shipments = [("Delhi", "PK-104"), ("Pune", "PK-105"),
             ("Delhi", "PK-106"), ("Kochi", "PK-107"),
             ("Pune", "PK-108")]
packages = defaultdict(list)

for city, tracking_id in shipments:
    packages[city].append(tracking_id)

print(dict(packages))
# {'Delhi': ['PK-104', 'PK-106'], 'Pune': ['PK-105', 'PK-108'], 'Kochi': ['PK-107']}

The grouping is deterministic: Delhi receives ['PK-104', 'PK-106'], Pune receives ['PK-105', 'PK-108'], and Kochi receives ['PK-107']. Keys retain their first-insertion order in the displayed dictionary.

Pass the callable as defaultdict(list), not defaultdict(list()). The latter passes an already-created list and raises TypeError. Reading packages["Jaipur"] returns [], but it also stores "Jaipur": [] in the mapping.

deque in Python: queues, bounded history and sliding windows

A deque supports append and pop at the right, plus appendleft and popleft at the left. A queue consumes its oldest item with popleft(), matching FIFO queue behaviour.

For a size-3 moving average over [4, 8, 6, 10, 12]:

  1. Window [4, 8, 6]: sum 4 + 8 + 6 = 18, average 18 / 3 = 6.0.

  2. Remove 4, append 10: window [8, 6, 10], sum 8 + 6 + 10 = 24, average 24 / 3 = 8.0.

  3. Remove 8, append 12: window [6, 10, 12], sum 6 + 10 + 12 = 28, average 28 / 3 = 9.333..., rounded to 9.33.

The exact result list is [6.0, 8.0, 9.33].

Deque sliding-window diagram shows three successive windows, with each outgoing value removed and a new value appended.

A bounded deque evicts automatically. After history = deque(["T1", "T2", "T3"], maxlen=3) and history.append("T4"), "T1" disappears and the result is deque(['T2', 'T3', 'T4'], maxlen=3). Make automatic eviction explicit when silent item loss would be a bug.

namedtuple, ChainMap and OrderedDict: records and mapping layers

A named tuple gives tuple values readable field names:

python
from math import sqrt

Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
x, y = p
distance = sqrt(3**2 + 4**2)  # sqrt(9 + 16) = sqrt(25) = 5.0
q = p._replace(x=6)

Here p.x == 3, unpacking gives x == 3 and y == 4, and q == Point(x=6, y=4). The original remains Point(x=3, y=4) because named tuples are immutable.

ChainMap searches mappings from first to last:

python
defaults = {"theme": "light", "page_size": 20}
user = {"theme": "dark"}
settings = ChainMap(user, defaults)

Now settings["theme"] == "dark" and settings["page_size"] == 20. Assigning settings["page_size"] = 50 writes to the first mapping. user becomes {"theme": "dark", "page_size": 50}, while defaults is unchanged.

Start an OrderedDict with [('compile', 2), ('test', 3), ('deploy', 1)]. After move_to_end("compile"), its key order is test, deploy, compile; popitem(last=False) then returns ('test', 3). Ordinary dictionaries preserve insertion order, so choose OrderedDict when explicit reordering, oldest-item removal or order-sensitive equality carries the logic.

Python collections mistakes: factories, mutation and access patterns

Match each failure to its repair:

  • defaultdict(list()) passes a list, not a callable. Use defaultdict(list).

  • p.x = 6 fails because a named tuple is immutable. Use p._replace(x=6).

  • Counter.elements() omits zero and negative counts. Inspect items() when those states matter.

  • ChainMap assignment writes only to its first mapping. Mutate the intended underlying mapping explicitly.

  • Frequent middle indexing is a poor deque access pattern. Use a list when random access dominates.

Bounded capacity is another trap. Given deque([1, 2, 3], maxlen=3), appendleft(0) silently removes 3 and produces deque([0, 1, 2], maxlen=3). Make automatic eviction explicit whenever losing an item could surprise the reader.

The choice checklist is therefore operational: count, group, process ends, model a record, layer settings or reorder keys.

Python collections exercises: predict the exact result

  1. Counter: letters = Counter("mississippi") gives m: 1, i: 4, s: 4, p: 2. letters.most_common(2) == [('i', 4), ('s', 4)]. Equal counts retain first-encounter order here, and i appears before s.

  2. Deque: start with d = deque([10, 20, 30], maxlen=3). After d.appendleft(5), the state is [5, 10, 20] because 30 is evicted from the right. After d.rotate(1), the final state is [20, 5, 10].

  3. Defaultdict: use defaultdict(set) to group [('red', 'A'), ('blue', 'B'), ('red', 'C'), ('blue', 'B')]. The logical result is red -> {'A', 'C'} and blue -> {'B'}. Repeating ('blue', 'B') does not duplicate B in a set.

Coding quizzes and interviews commonly test output prediction, factory selection, mutation and edge cases.

Python collections module: the short version and next step

Container

Core job

Counter

Count values

defaultdict

Initialise missing values and group items

deque

Work efficiently at both ends

namedtuple

Store immutable named fields

ChainMap

Search mapping layers

OrderedDict

Perform explicit order operations

Choose the container from the operation, then test its edge case: missing keys, non-positive counts, immutability or bounded eviction. Continue with the Python course for a complete language path. If your immediate goal is implementing data structures and solving problems, follow DSA Using Python instead.