数据类:如何使用asdict()忽略None值?

时间:2019-07-01 16:17:26

标签: python python-dataclasses

@dataclass
class Car:
    brand: str
    color: str

如何获取忽略None值的字典?像这样:

>>> car = Car(brand="Audi", color=None)
>>> asdict(car, some_option_to_ignore_none_values=True)
> {'brand': 'Audi'}

6 个答案:

答案 0 :(得分:1)

您在这里:

from dataclasses import dataclass


@dataclass
class Car:
    brand: str
    color: str


def asdict(o, skip_empty=False):
    return {k: v
            for k, v in o.__dict__.items()
            if not (skip_empty and v is None)}


if __name__ == '__main__':
    c = Car(brand='BMW', color=None)
    print(asdict(c, skip_empty=False))
    print(asdict(c, skip_empty=True))

打印:

{'brand': 'BMW', 'color': None}
{'brand': 'BMW'}

答案 1 :(得分:1)

另一种选择是编写一个dict_factory,该工厂将拒绝添加None值并将其传递给asdict方法。 在https://github.com/python/cpython/blob/master/Lib/dataclasses.py

处查看代码源

答案 2 :(得分:0)

我需要递归的东西,所以我借鉴了拉姆丁指向的数据类源代码并添加了一些条件:

from copy import deepcopy
from dataclasses import fields

def dict_minus_none_values(obj, dict_factory=dict):
    """Based on dataclasses._asdict_inner"""
    if hasattr(type(obj), "__dataclass_fields__"):
        result = []
        for field in fields(obj):
            value = dict_minus_none_values(getattr(obj, field.name), dict_factory)
            if value is not None:
                result.append((field.name, value))
        return dict_factory(result)
    if isinstance(obj, tuple) and hasattr(obj, "_fields"):
        return type(obj)(*[dict_minus_none_values(v, dict_factory) for v in obj])
    if isinstance(obj, (list, tuple)):
        return type(obj)(dict_minus_none_values(v, dict_factory) for v in obj)
    if isinstance(obj, dict):
        return type(obj)(
            (
                dict_minus_none_values(k, dict_factory),
                dict_minus_none_values(v, dict_factory),
            )
            for k, v in obj.items()
            if v is not None
        )
    return deepcopy(obj)

答案 3 :(得分:0)

class IgnoreNoneValues(dict):
    def __setitem__(self, k, v):
        if v is not None:
            super().__setitem__(k, v)

asdict(<some dataclass object>, dict_factory=IgnoreNoneValues)

答案 4 :(得分:0)

使用简单的类

class human:
  def __init__(self, choice = False, **kwargs):
    self.details = [kwargs if choice is False else self._filterr(kwargs)][0]

  def _filterr(self, param):
    filtered = {k:v for k,v in param.items() if v is not None}
    return filtered

jason = human(choice = True ,name = "jason", age = None, height = None, gender = None, programmer = True)

print(jason.details)
{'name': 'jason', 'programmer': True}

[Program finished]

答案 5 :(得分:0)

所有答案都很好,但对我来说它们太冗长了。这是一个单行:

# dc is dataclass
# d is dict out
d = asdict(dc, dict_factory=lambda x: {k: v for (k, v) in x if v is not None})

展示案例:

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

s1 = Space(size=2)
s1_dict = asdict(s1, dict_factory=lambda x: {k: v for (k, v) in x if v is not None})
print(s1_dict)
# {"size": 2}

s2 = Space(dtype='int', shape=(2, 5))
s2_dict = asdict(s2, dict_factory=lambda x: {k: v for (k, v) in x if v is not None})
print(s2_dict)
# {"dtype": "int", "shape": (2, 5)}