Python数据类:是否可以为字段设置默认默认值?

时间:2019-10-25 07:31:15

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

我想创建一个数据类基类,其中子类中的所有字段都是自动可选的,并且默认为无(如果未提供默认值)。

以下代码...似乎可以满足我的要求,但不能完全做到。发生错误的方式与我从未写过__init_subclass__(即抱怨未填充的参数)的方式相同……也许是因为我的代码在 之后运行了? >

@dataclass(order=True, frozen=True)
class BaseDictKey:
    def __init_subclass__(cls, *args, **kwargs):
        super().__init_subclass__(*args, **kwargs)
        # noinspection PyUnresolvedReferences
        for field in cls.__dataclass_fields__.values():
            field.default = None if field.default is None else field.default
            field.type = typing.Union[field.type, NoneType]

@dataclass(order=True, frozen=True)
class ScoreDictKey(BaseDictKey):
    catalog: str  # magically becomes catalog: Optional[str] = None
    dataset: str = 'foo'  # magically becomes dataset: Optional[str] = 'foo'

(如果您想知道为什么要这样做,我还有一个使用这些BaseDictKeys的基类,它期望子类中的所有字段都是可选的。我想我可以引发异常如果我检测到某些不是“可选”内容,那看起来就很丑。)

在Python 3.7+中这可能吗?

1 个答案:

答案 0 :(得分:1)

我找到了一种方法,可以修改类__annotations__的字段以使字段为可选,并直接在类上设置属性以提供默认值None

from dataclasses import dataclass

import typing


@dataclass(order=True, frozen=True)
class BaseDictKey:
    def __init_subclass__(cls, *args, **kwargs):
        for field, value in cls.__annotations__.items():
            cls.__annotations__[field] = typing.Union[value, None]
            if not hasattr(cls, field):
                setattr(cls, field, None)
        super().__init_subclass__(*args, **kwargs)


@dataclass(order=True, frozen=True)
class ScoreDictKey(BaseDictKey):
    catalog: str  # magically becomes catalog: Optional[str] = None
    dataset: str = 'foo'  # magically becomes dataset: Optional[str] = 'foo'

    def __init__(self, *args, **kwargs):  # to get rid of PyCharm warning
        pass


c = ScoreDictKey()
print(c.catalog, c.dataset)  # None foo