如何删除数据类属性

时间:2019-09-26 15:06:45

标签: python python-3.x python-dataclasses

我有一个像这样的数据类:

@dataclass
class Bla:
    arg1: Optional[int] = None
    arg2: Optional[str] = None
    arg3: Optional[Dict[str, str]] = None

我想要这种行为:

>>> bla = Bla(arg1=None, arg2=None, arg3=None)
>>> asdict(bla)
{'arg1': None, 'arg2': None, 'arg3': None}

>>> bla = Bla()
{}

在这种情况下,我可以使用dict,但是我将失去具有类型提示(并使用mypy)的可能性

所以我尝试了这个:

class none:
    ...

@dataclass
class Bla:
    arg1: Union[none, int] = none()
    arg2: Union[none, str] = none()
    arg3: Union[none, Dict[str, str]] = none()

    def __post_init__(self) -> None:
        for k, v in self.__dict__.copy().items():
            if isinstance(v, none):
                delattr(self, k)

但是结果是:

>>> asdict(Bla())
{'arg1': <__main__.none object at 0x7f71bc0159b0>, 'arg2': <__main__.none object at 0x7f71bc015a90>, 'arg3': <__main__.none object at 0x7f71bc015ac8>}

我希望有一个空的dict

如果尝试:

>>> a = Bla(None, None, None)
>>> del a.__dict__["arg1"]
>>> asdict(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/(....)/venv/lib/python3.6/site-packages/dataclasses.py", line 1011, in asdict
    return _asdict_inner(obj, dict_factory)
  File "/home/(...)/venv/lib/python3.6/site-packages/dataclasses.py", line 1018, in _asdict_inner
    value = _asdict_inner(getattr(obj, f.name), dict_factory)
AttributeError: 'Bla' object has no attribute 'arg1'

如何以一种可以在以后使用asdict的方式从数据类对象中动态删除属性?

2 个答案:

答案 0 :(得分:1)

这不是您有关从数据类中删除属性的问题的答案,但它提供了一种获取自定义asdict的机制,其行为符合您想要的方式:

from dataclasses import dataclass
from typing import Optional, Dict, cast

SENTINEL = cast(None, object())  # have a sentinel that pretends to be 'None'


@dataclass
class Bla:
    arg1: Optional[int] = SENTINEL
    arg2: Optional[str] = SENTINEL
    arg3: Optional[Dict[str, str]] = SENTINEL

    def asdict(self):
        return {k: v for k, v in self.__dict__.items() if v is not SENTINEL}

一些测试:

>>> Bla().asdict()
{}
>>> Bla(None, None).asdict()
{'arg1': None, 'arg2': None}
>>> Bla(1, 'foo', None).asdict()
{'arg1': 1, 'arg2': 'foo', 'arg3': None}

但是请记住,这全是谎言,并且在显式调用时属性仍然存在:

>>> print(Bla().arg1)
<object object at 0x7fc89ed84250>

答案 1 :(得分:0)

我的问题是关于如何以一种可以使用函数dataclasses.dataclass来生成字典的方式从dataclasses.asdict对象中删除属性。

我的用例是许多我想以易于序列化和类型提示的方式存储的模型,但是有可能忽略元素(没有任何默认值)。我的第一种方法是找出删除dataclass构造函数中未明确传递的所有项目的方法。

但是,正如Patrick and Arne明智地指出的那样,用dataclasses来完成任务并不是正确的选择。

我发现解决用例的最佳方法是使用typing_extensions模块中的TypedDict,它将与PEP 589一起成为模块{中的标准库的一部分Python 3.8中的{1}}。

在Python 3.8中:

typing

在其他版本中,您必须安装from typing import TypedDict, Dict class Bla(TypedDict): arg1: int arg2: str arg3: Dict[str, str] 模块:

typing_extensions

然后:

pip install typing-extensions

让我们尝试一下:

from typing_extensions import TypedDict

非常优雅,非常适合我的用例。

唯一的缺点是>>> Bla(arg1=1, arg2="bla", arg3={"bla":"bla"}) {'arg1': 1, 'arg2': 'bla', 'arg3': {'bla': 'bla'}} >>> Bla(arg1=1, arg2="bla") {'arg1': 1, 'arg2': 'bla'} >>> Bla(arg1=1) {'arg1': 1} 还不支持默认值。有一个PR,我希望他们能有所作为。