Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python dataclasses: omit field from asdict

I've started making heavy use of the python dataclasses module and find it very useful. I especially like the flags that can be set on each field allowing for toggling of compare, init etc.

I often find however that there is a field which I wish to omit from the asdict behaviour of the class. In some situations this may be possible with the dict_factory argument, but it sometimes happens that a field will cause the asdict function to raise an exception before it is omitted through use of the dict_factory.

Can anyone else suggest a clean way to do this? Would it not be a useful additional flag to add to the dataclasses module?

like image 262
kerzane Avatar asked Dec 09 '25 07:12

kerzane


2 Answers

I've ended up defining dict_factory in dataclass as staticmethod and then using in as_dict(). Found it more straightforward than messing with metadata.

from typing import Optional, Tuple
from dataclasses import asdict, dataclass

@dataclass
class Space:
    size: Optional[int] = None
    dtype: Optional[str] = None
    shape: Optional[Tuple[int]] = None

    @staticmethod
    def dict_factory(x):
        exclude_fields = ("shape", )
        return {k: v for (k, v) in x if ((v is not None) and (k not in exclude_fields))}


s1 = Space(size=2)
s1_dict = asdict(s1, dict_factory=Space.dict_factory)
print(s1_dict)
# {"size": 2}

s2 = Space(dtype='int', shape=(2, 5))
s2_dict = asdict(s2, dict_factory=Space.dict_factory)
print(s2_dict)
# {"dtype": "int"}
# no "shape" key, because it is excluded in dict_factory of the class.
like image 89
Victor Di Avatar answered Dec 10 '25 19:12

Victor Di


You can add custom metadata to field like field(metadata={"include_in_dict":True}) and in the dict_factory you can check this before anything else and skip the field if needed.

if field_.metadata.get("include_in_dict", False):
    continue
like image 41
Mateus Terra Avatar answered Dec 10 '25 21:12

Mateus Terra