I am having trouble setting up a simple dataclass using a new defaultdict(dict).
If I tell the factory to use 'dict' as below , instantiation fails with typerror collection.defaultdict object is not callable
from collections import defaultdict
from dataclasses import dataclass, field
@dataclass
class ResultSet:
changed: bool = False
mqttdata: defaultdict(dict) = field(default_factory=defaultdict(dict)) # does not work!
It does sorta work using field(default_factory=defaultdict) but then my code will fail later when it encounters missing keys - presumably because defaultdict was not set up for dict.
How do I properly set up a new defaultdict(dict) in a dataclass?
CodePudding user response:
You have a few problems with the code and how you are using dataclasses currently:
Type generics in annotations need to be specified through square brackets
[]generally, sodefault[dict]instead ofdefaultdict(dict)for example.The
default_factoryargument todataclasses.field()needs to be a no-arg callable which returns a new object with default values set. For example, assuming you have a nested dataclassInnerwhich specifies defaults for all fields, you could usedefault_factory=Innerto create a newInnerobject each time the main dataclass is instantiated.Note that the
default_factoryargument is mainly useful for mutable types such asset,list, anddict, so that the same object isn't shared (and potentially mutated) between dataclass instances.
Putting it all together, here is the working code which sets a default value for a field of type defaultdict[dict]:
from collections import defaultdict
from dataclasses import dataclass, field
@dataclass
class ResultSet:
changed: bool = False
mqttdata: defaultdict[dict] = field(default_factory=lambda: defaultdict(dict)) # works!
print(ResultSet())
In Python versions earlier than 3.9, which is when PEP 585 was introduced, you'll need to add the following import at the top so that any type annotations are lazy-evaluated:
from __future__ import annotations
