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_factory
argument 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 dataclassInner
which specifies defaults for all fields, you could usedefault_factory=Inner
to create a newInner
object each time the main dataclass is instantiated.Note that the
default_factory
argument 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