dict.fromkeys()
Class method — build a fresh dict from a set of keys, with every key pointing at the same default value.
Common call
dict.fromkeys(keys, 0)
Returns
a new dict — all values are the SAME object
Replaces
`{k: default for k in keys}` when the default is immutable
Watch out
default is SHARED — dict.fromkeys(keys, []) gives every key the SAME list
dict.fromkeys(iterableiterable — Any iterable of hashable keys. Duplicates collapse (last one wins, but they all get the same value).type: iterable · required, valuevalue — The default value for every key. Not copied — every key points at the exact same object.type: Any · default: None=None)
→ dict
Demo
Live evaluation
Try:
Inputs
keyslistcomma-separated keys
valueAnydefault value
Output
['a', 'b', 'c'].fromkeys('0')
{'a': '0', 'b': '0', 'c': '0'}
The demo shows the resulting dict. Duplicate keys in the input collapse (only one entry per key). The critical thing NOT visible in this demo — because we pass strings — is the shared-reference behavior: if you passed a mutable default like [] or {}, every key would point at THE SAME list or dict. See pitfalls.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| iterable | iterable | yes | Any iterable of hashable keys. Duplicates collapse (last one wins, but they all get the same value). |
| value | Any | no (None) | The default value for every key. Not copied — every key points at the exact same object. |
Return value
dict — A NEW dict with keys from the iterable, all mapped to the SAME value. The value is not copied — every key shares the exact same object reference.
Common patterns
Initialize counters at zero
Immutable defaults like 0, "", and None are safe to share.
counts = dict.fromkeys(categories, 0)
Deduplicate while preserving order
Only the keys matter — the value is throwaway. Since 3.7 the key order is preserved.
unique = list(dict.fromkeys(items)) # order-preserving dedup
Set of allowed keys with None values
A skeleton dict that the caller will populate.
template = dict.fromkeys(fields) # every field mapped to None
Examples
1. Basic
dict.fromkeys(["a", "b", "c"], 0)
Returns
{"a": 0, "b": 0, "c": 0}2. Default value is None
dict.fromkeys(["x", "y"])
Returns
{"x": None, "y": None}3. Order-preserving dedup
list(dict.fromkeys([3, 1, 2, 1]))
Returns
[3, 1, 2]4. Duplicates collapse
dict.fromkeys("aabbcc")
Returns
{"a": None, "b": None, "c": None}5. From a range
dict.fromkeys(range(3), "unset")
Returns
{0: "unset", 1: "unset", 2: "unset"}Pitfalls
1. Mutable default is SHARED across all keys
The single most-copied footgun with fromkeys. The value is not copied — every key points at the SAME object. Appending to one key's list appears at every key.
Same list everywhere
d = dict.fromkeys(["a", "b"], []) d["a"].append(1) d
{"a": [1], "b": [1]} # both keys see the append
Comprehension makes copies
d = {k: [] for k in ["a", "b"]} d["a"].append(1) d
{"a": [1], "b": []}
2. It is a CLASS method, not an instance method
Called on the dict class, not on a dict instance. Calling on an instance works but reads awkwardly.
Confusing style
{"a": 1}.fromkeys(["x", "y"]) # ignores the receiver!
{"x": None, "y": None} # values NOT copied from the receiver
Class form
dict.fromkeys(["x", "y"])
{"x": None, "y": None}
3. Unhashable keys raise TypeError
Every key must be hashable. A list or dict in the iterable trips.
Unhashable
dict.fromkeys([[1, 2], [3, 4]])
TypeError: unhashable type: 'list'
Tuple keys
dict.fromkeys([(1, 2), (3, 4)])
{(1, 2): None, (3, 4): None}
4. The value is NOT type-checked against the keys
Any value type works — including a value that would be misleading given the domain. A common mistake is passing a callable, expecting each key to invoke it.
Same reference
d = dict.fromkeys(["a", "b"], list)
{"a": <class list>, "b": <class list>}
Comprehension calls it
d = {k: list() for k in ["a", "b"]}
{"a": [], "b": []} # separate lists
When to use
Use it
- Initializing counters or flags with an immutable default (0, None, "")
- Order-preserving deduplication of a list
- Building a skeleton dict where the caller will populate values
- Creating a "set with values" where every entry has the same tag
Reach for something else
- Mutable default value → use a dict comprehension instead
- Per-key computed defaults → dict comprehension or setdefault
- Deep-copy semantics needed → comprehension with copy() or deepcopy()
- Very large key iterables where a comprehension is more readable
Notes
Complexity
O(n) — one pass over the iterable
Return
A new dict; when called on a subclass, returns an instance of that subclass
CPython impl
Objects/dictobject.c :: dict_fromkeys_impl
Memory
One dict allocated; the value is stored by reference, not copied
Thread-safe
Yes — creation is a pure operation
FAQ
It builds a new dict from scratch — it does not need an existing dict to work with. Making it a classmethod keeps the API consistent: `dict.fromkeys(...)` reads like a factory call.
History
2.3
fromkeys() introduced as a class method on dict.
3.7
Insertion order preserved — enables the popular order-preserving dedup idiom.