Python 数据类:你能为字段设置默认值吗?
Python dataclass: can you set a default default for fields?
我想做一个数据class基础class,其中子classes中的所有字段都是自动可选的,默认为None(如果没有默认是提供)。
以下代码...似乎几乎可以满足我的要求,但不完全是。它出错的方式就像我从未写过 __init_subclass__
一样(即抱怨未填充的参数)......也许是因为我的代码是 运行 after数据class 奇迹发生了?
@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 的 baseclass,它期望 subclasses 中的任何和所有字段都是可选的。我想如果我检测到某些东西不是可选的,我 可以 相反引发异常,但这看起来更丑陋。)
这在 Python 3.7+ 中可能吗?
我找到了一种修改 class __annotations__
字段以使字段成为可选字段并直接在 class 上设置属性以提供默认值的方法 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
我想做一个数据class基础class,其中子classes中的所有字段都是自动可选的,默认为None(如果没有默认是提供)。
以下代码...似乎几乎可以满足我的要求,但不完全是。它出错的方式就像我从未写过 __init_subclass__
一样(即抱怨未填充的参数)......也许是因为我的代码是 运行 after数据class 奇迹发生了?
@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 的 baseclass,它期望 subclasses 中的任何和所有字段都是可选的。我想如果我检测到某些东西不是可选的,我 可以 相反引发异常,但这看起来更丑陋。)
这在 Python 3.7+ 中可能吗?
我找到了一种修改 class __annotations__
字段以使字段成为可选字段并直接在 class 上设置属性以提供默认值的方法 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