10
@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'}
4

6 回答 6

5

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

# 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)}
于 2021-08-02T20:24:31.130 回答
2

另一种选择是编写一个 dict_factory 拒绝添加 None 值并将其传递给asdict方法。在此处查看代码源https://github.com/python/cpython/blob/master/Lib/dataclasses.py

于 2019-09-11T17:47:15.983 回答
0

我需要一些递归的东西,所以我从 Ramtin 指向的数据类源代码中借用并添加了几个条件:

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)
于 2020-05-19T21:13:26.827 回答
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)
于 2021-05-06T09:45:06.930 回答
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]
于 2021-05-17T02:03:51.150 回答
-2

干得好:

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'}
于 2019-07-01T16:30:43.830 回答