Search code examples
pythonpython-dataclasses

dataclasses: how to ignore default values using asdict()?


I would like to ignore the default values after calling asdict()

@dataclass
class A:
    a: str
    b: bool = True

so if I call

a = A("1")
result = asdict(a, ignore_default=True) 
assert {"a": "1"} == result  # the "b": True should be deleted

Solution

  • The dataclasses module doesn't appear to have support for detecting default values in asdict(), however the dataclass-wizard library does -- via skip_defaults argument.

    Example:

    from dataclasses import dataclass
    from dataclass_wizard import asdict
    
    @dataclass
    class A:
        a: str
        b: bool = True
    
    a = A("1")
    result = asdict(a, skip_defaults=True)
    assert {"a": "1"} == result  # the "b": True should be deleted
    

    Further, results show it is close to 2x faster than an approach with dataclasses.adict(). I've added benchmark code I used for testing below.

    from dataclasses import dataclass, asdict as asdict_orig, MISSING
    from timeit import timeit
    
    from dataclass_wizard import asdict
    
    @dataclass
    class A:
        a: str
        b: bool = True
    
    
    def asdict_factory(cls):
        def factory(obj: list[tuple]) -> dict:
            d = {}
            for k, v in obj:
                field_value = cls.__dataclass_fields__[k].default
                if field_value is MISSING or field_value != v:
                    d[k] = v
            return d
    
        return factory
    
    a = A("1")
    A_fact = asdict_factory(A)
    
    print('dataclass_wizard.asdict():  ', timeit('asdict(a, skip_defaults=True)', globals=globals()))
    print('dataclasses.asdict():       ', timeit('asdict_orig(a, dict_factory=A_fact)', globals=globals()))
    
    result1 = asdict(a, skip_defaults=True)
    result2 = asdict_orig(a, dict_factory=A_fact)
    
    assert {"a": "1"} == result1 == result2
    
    a2 = A("1", True)
    a3 = A("1", False)
    assert asdict(a2, skip_defaults=True) == asdict_orig(a2, dict_factory=A_fact)
    assert asdict(a3, skip_defaults=True) == asdict_orig(a3, dict_factory=A_fact)
    

    Disclaimer: I am the creator and maintainer of this library.