Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

Python Defaultdict Get Returns None: Missing Defaults Apply to Indexing

A defaultdict factory works with brackets but not with get. Choose whether lookup should create a key.

By ON Lab2 min readSources checked November 10, 2026 (KST)

defaultdict calls its default factory for missing-key indexing. get does not invoke that missing-key mechanism, so it returns its explicit default or None without inserting a key.

Check the failure with a small fixture

A defaultdict factory works with brackets but not with get. Choose whether lookup should create a key.

from collections import defaultdict
buckets = defaultdict(list)
assert buckets.get("alpha") is None
assert "alpha" not in buckets
assert buckets.get("alpha", []) == []
assert "alpha" not in buckets
buckets["alpha"].append("event")
assert buckets["alpha"] == ["event"]
assert buckets.get("alpha") == ["event"]
assert "beta" not in buckets
assert buckets["beta"] == []
assert "beta" in buckets

What the result means

The two read styles differ in side effects. Indexing beta creates a bucket even though nothing is appended. get with [] returns a fallback list for that call, but mutating such a fallback does not automatically insert it into the mapping. This can make a collector appear to lose data if it appends through get instead of creating or retrieving an owned bucket.

Choose the correction for your caller

Use brackets when missing keys should become real buckets. Use get for an observation that should leave the mapping unchanged. For a plain dictionary, setdefault can establish an entry while returning its value, but the default expression is evaluated on every call. Keep the factory callable itself, such as list, rather than calling it at construction. Decide whether an empty bucket is meaningful application state before relying on membership tests.

Limits and the next check

This example covers a single-threaded mapping. A sequence of lookup, construction and mutation is not a complete concurrent aggregation policy. A custom dict subclass can define other missing behavior, so check its actual contract rather than assuming every mapping has defaultdict semantics.

Related: Compare a related data or execution contract.

The embedded Python example was executed as an isolated local script on November 10, 2026 (KST), using Python 3.11.6. It demonstrates the stated boundary; it is not a test of your application or a promise of compatibility with every Python release.

Sources & further reading