Course topics

By WebNest Studio

Python Tutorial

The collections Module

The collections module provides specialised containers that make common tasks shorter and faster than with plain dicts and lists: counting things, grouping items, fixed records with names, double-ended queues, chaining configuration layers, and more.

This lesson covers Counter, defaultdict, OrderedDict, deque, namedtuple, ChainMap, and the UserDict/UserList base classes, each with a practical example.

Counter

Counter(iterable) counts hashable items. most_common(n) returns the top items, missing keys count as 0, and counters support +, -, & and |. Perfect for word frequencies, votes, and inventory.

defaultdict

defaultdict(factory) creates a missing key's value automatically by calling the factory: defaultdict(list) for grouping, defaultdict(int) for counting, defaultdict(set) for unique grouping. No more if key not in d checks.

OrderedDict, deque, namedtuple, ChainMap

OrderedDict remembers order (like dict) and adds move_to_end() and order-sensitive equality — handy for LRU caches. deque is the double-ended queue. namedtuple makes tuple records with field names. ChainMap searches several dicts in order — e.g. command-line options, then environment, then defaults — without copying them.

UserDict and UserList

To create your own dict-like or list-like class, subclass UserDict or UserList: they route all operations through your overridden methods, which is more reliable than subclassing the built-in dict directly.

Examples

Counter for frequencies

Python
from collections import Counter

text = "the quick brown fox jumps over the lazy dog the end"
words = Counter(text.split())
print(words.most_common(2))
print(words["the"], words["cat"])

votes = Counter(["python", "java", "python", "go", "python", "java"])
print(votes)
stock = Counter(pens=10, books=4)
sold = Counter(pens=3, books=4)
print(stock - sold, sorted((stock + sold).elements())[:3])
Output
[('the', 3), ('quick', 1)]
3 0
Counter({'python': 3, 'java': 2, 'go': 1})
Counter({'pens': 7}) ['books', 'books', 'books']

defaultdict for grouping and counting

Python
from collections import defaultdict

orders = [("Asha", "pen"), ("Ravi", "book"), ("Asha", "bag"), ("Asha", "pen")]
by_customer = defaultdict(list)
unique_items = defaultdict(set)
counts = defaultdict(int)
for customer, item in orders:
    by_customer[customer].append(item)
    unique_items[customer].add(item)
    counts[customer] += 1

print(dict(by_customer))
print({k: sorted(v) for k, v in unique_items.items()})
print(dict(counts))
Output
{'Asha': ['pen', 'bag', 'pen'], 'Ravi': ['book']}
{'Asha': ['bag', 'pen'], 'Ravi': ['book']}
{'Asha': 3, 'Ravi': 1}

OrderedDict as an LRU cache, and ChainMap for layered settings

Python
from collections import OrderedDict, ChainMap

class LRUCache:
    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)     # evict least recently used

cache = LRUCache(2)
cache.put("a", 1); cache.put("b", 2); cache.get("a"); cache.put("c", 3)
print(list(cache.data))

defaults = {"theme": "light", "language": "en", "page_size": 20}
env = {"language": "hi"}
cli = {"page_size": 50}
settings = ChainMap(cli, env, defaults)
print(settings["theme"], settings["language"], settings["page_size"])
Output
['a', 'c']
light hi 50

UserDict: a dictionary with case-insensitive keys

Python
from collections import UserDict

class CaseInsensitiveDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key.lower(), value)

    def __getitem__(self, key):
        return super().__getitem__(key.lower())

headers = CaseInsensitiveDict()
headers["Content-Type"] = "application/json"
print(headers["content-type"], headers["CONTENT-TYPE"], dict(headers))
Output
application/json application/json {'content-type': 'application/json'}

Common Mistakes

  • Writing manual counting loops instead of Counter.
  • Checking "if key not in d: d[key] = []" everywhere instead of defaultdict(list).
  • Printing a defaultdict and being surprised that simply reading a missing key created it.
  • Subclassing dict and overriding __setitem__, which update() and the constructor bypass; use UserDict.

Key Points to Remember

  • Counter counts items and finds the most common.
  • defaultdict creates missing values automatically (list, int, set...).
  • OrderedDict adds move_to_end/popitem(last=False) for LRU-style logic.
  • deque, namedtuple and ChainMap cover queues, records and layered lookups.
  • UserDict/UserList are the safe bases for custom containers.

Practice the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.