We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modelling Data with Dataclasses step 3 of 28
Find Mutable Defaults That Instances Share
Python creates a field's default value once, when it defines the class. If
that value is a list, every object that uses the default shares one list.
The dataclass decorator refuses items: list[str] = [], but it misses other
cases. The Bag class in the starter holds a list, and the decorator
accepts bag: Bag = Bag(). A default factory causes the same sharing if
it returns the same list every time.
Write an inspector that finds these fields.
solve("Leaky")
# ["bag", "rows"]
What to write
Fill in audit_defaults(cls). Loop over dataclasses.fields(cls) and return
the names of the fields you flag, sorted alphabetically.
- Inspect every field, including fields with
init=False. - Do not create an instance of
cls, and do not change its fields. dataclasses.MISSINGis the marker that a field'sdefaultanddefault_factoryhold when you gave none. Test each one withis not MISSING. A default ofNone,0or""is a real default.- Never flag a field that has neither a default nor a factory.
Rule 1: a plain default
Flag the field unless its default passes this check:
- Accept a value when
isinstancematches any oftype(None),bool,int,float,complex,str,bytesortype. Useisinstance, not an exact type comparison. - Accept a
tupleorfrozensetwhen every element passes this same check. An empty one passes. - Reject every other value.
So (1, "x") passes, and (1, Bag()) fails because a Bag is none of
the accepted types.
Rule 2: a default factory
- Call the factory exactly twice, and flag the field if the two results are the same object.
- Compare them with
is, not==, and do not apply rule 1 to them. - Keep both results alive while you compare them.
id(f()) == id(f())can beTruefor two new lists, because Python frees the first list and reuses its memory for the second.
list, dict and set build a new container on each call.
_shared_factory and _shared_index return the same module-level object
each time, so your inspector flags their fields.
Expected reports
Keep the classes and solve as they are. solve takes a name from
REGISTRY and returns your report:
| Target | Result |
|---|---|
| Safe | [] |
| Leaky | ["bag", "rows"] |
| Nested | ["combo"] |
| Empty | [] |
| Cache | ["index"] |
Leaky.bag fails rule 1. Leaky.rows fails rule 2. Leaky.ok passes,
because its factory returns a new list on each call. Cache.seeded has init=False and a list
factory, so you inspect it and it passes.
Your code must pass mypy --strict. DataclassInstance is a type that
exists only for the type checker and means "any dataclass instance". That
is why the starter imports it under if TYPE_CHECKING: and writes it in
quotes. Keep both as they are.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Python reference solution
Sign in to track your attempts toward unlocking the reference solution.