AI Skill Report Card
Working with Python Dict and Frozendict
Quick Start13 / 15
Python# Mutable mapping d = {"a": 1, "b": 2} d["c"] = 3 d.update(x=10) # Immutable mapping (frozendict, added as a builtin in newer Python) fd = frozendict({"a": 1, "b": 2}) # fd["a"] = 99 # raises TypeError: object does not support item assignment # Convert between them d2 = dict(fd) fd2 = frozendict(d2)
Recommendation▾
Note that frozendict is not a Python builtin/stdlib type (as of most versions) — clarify it requires the third-party 'frozendict' package or Python 3.13+ optional module, since the skill implies it's built-in which could mislead.
Workflow12 / 15
Progress:
- Determine if the mapping needs to be mutable (
dict) or immutable/hashable (frozendict) - Choose construction method (literal,
dict()/frozendict()constructor, comprehension,fromkeys) - Use appropriate access patterns (
[],.get(),.setdefault()for dict only) - Iterate via
.keys(),.values(),.items()view objects - Apply merge/update via
|and|=(dict) or|(frozendict, returns new frozendict) - Use
frozendictwhen a mapping must be a dict key, set member, or passed as an immutable default/config
1. Construction
Pythond = dict(a=1, b=2) d = {k: v for k, v in pairs} d = dict.fromkeys(["a", "b"], 0) fd = frozendict(a=1, b=2) fd = frozendict({"a": 1}) fd = frozendict(zip(keys, values))
2. Access and mutation
- Both support
d[key],d.get(key, default),key in d,len(d). - Only
dictsupportsd[key] = value,del d[key],.pop(),.popitem(),.clear(),.update(),.setdefault(). frozendictraisesTypeErroron any mutation attempt — treat it liketuplevslist.
3. Views and iteration
Pythonfor k, v in d.items(): ... keys_view = d.keys() # dynamic view, reflects later dict changes values_view = d.values() items_view = d.items() # set-like if values are hashable
frozendict also exposes .keys(), .values(), .items(), but views are effectively static since the underlying mapping can't change.
4. Merging
Pythonmerged = d1 | d2 # new dict d1 |= d2 # in-place update, dict only merged_fd = fd1 | fd2 # new frozendict, no in-place |= (would require mutation)
5. Hashability
Pythonconfig = frozendict(timeout=30, retries=3) cache = {config: "result"} # valid: frozendict is hashable if all values are hashable # {d: "result"} # invalid: dict is unhashable, raises TypeError
Recommendation▾
Add a bad-outcome example (e.g., someone mutating a frozendict and hitting TypeError, or a subtle bug from shallow immutability) to strengthen the examples section per best practices.
Examples12 / 20
Example 1: Input: Need a default function argument that's a mapping and must avoid the mutable-default-argument bug. Output:
Pythondef process(options: frozendict = frozendict()): ...
Using frozendict() as a default is safe because it can never be mutated, unlike {}.
Example 2: Input: Need to use a set of key-value options as a dictionary key for memoization. Output:
Pythonfrom functools import lru_cache @lru_cache def compute(params: frozendict): ... compute(frozendict(x=1, y=2))
Example 3: Input: Convert a JSON-decoded dict into an immutable config object. Output:
Pythonimport json raw = json.loads(payload) config = frozendict(raw)
Recommendation▾
The examples section is somewhat thin (3 examples, all 'good' outcomes) — include a contrasting incorrect approach and its failure mode for deeper comparative learning.
Best Practices
- Default to
dictfor general-purpose, mutable mappings; reach forfrozendictonly when immutability or hashability is required. - Use dict/frozendict comprehensions instead of building via loops.
- Prefer
.get()overtry/except KeyErrorfor optional lookups with defaults. - Use
|for merging in Python 3.9+ instead of{**d1, **d2}for readability. - Nest
frozendictinsidefrozendict(notdict) if you need deep immutability — afrozendictcontaining adictvalue is still mutable through that inner value. - Document API boundaries (e.g., public function signatures) with
frozendictto signal "read-only" intent to callers.
Common Pitfalls
- Assuming
frozendictdeep-freezes nested structures — it only prevents top-level key/value reassignment. - Trying to use
frozendictas a drop-in fordictin code that calls mutating methods (update,pop, etc.) — this raisesTypeErrorat runtime, not at type-check time unless annotated. - Using a plain
dictas a cache key or set element — raisesTypeError: unhashable type: 'dict'. - Forgetting that dict view objects (
.keys(),.items()) are live views over a mutabledict; mutating the dict during iteration raisesRuntimeError: dictionary changed size during iteration. - Assuming
frozendict | dictmutates the frozendict — it always returns a new object.