英文:
how can I narrow dataclass annotations (i.e., how can I update type hints after handling default None in post_init)?
问题
以下是代码的中文翻译部分:
我有一个数据类,它可以接受一个关键字值,或者如果未指定值,则可以从其他属性推断出一个值。
import dataclasses
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
secondary: float | None = None
def __post_init__(self):
if self.secondary is None:
self.secondary = self.primary
这段代码有效,但它让我在`.secondary`的类型提示中被困扰,即使在`__post_init__`之后`.secondary`*绝对不可能*是`None`。
在`__post_init__`中对`self.secondary`进行`cast`操作不起作用。但这个方法起作用:
NULL_FLOAT = float(int(uuid.uuid4())
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
secondary: float = NULL_FLOAT
def __post_init__(self):
if self.secondary == NULL_FLOAT:
self.secondary = self.primary
但这种方法感觉不太符合Python的风格。
以下方法也有效:
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
_secondary: float | None = None
def __post_init__(self):
if self._secondary is None:
self.secondary = self.primary
else:
self.secondary = self._secondary
或者这种方法也可以:
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
_secondary: float | None = None
@property
def secondary(self) -> float:
if self._secondary is None:
self.secondary = self.primary
else:
self.secondary = self._secondary
但后两种方法只是为了类型缩小而操纵我的kwargs,这种做法有点不太对。
我漏掉了什么?
英文:
I have a dataclass that can take a keyword value, or, if no value is specified, infer a value from other attributes.
import dataclasses
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
secondary: float | None = None
def __post_init__(self):
if self.secondary is None:
self.secondary = self.primary
This code works, but it leaves me stuck with float | None
as the type hint for .secondary
even though .secondary
cannot possibly be None
after __post_init__
.
cast
-ing self.secondary
in __post_init__
doesn't work. This does:
NULL_FLOAT = float(int(uuid.uuid4())
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
secondary: float = NULL_FLOAT
def __post_init__(self):
if self.secondary == NULL_FLOAT:
self.secondary = self.primary
But it feels distinctly non-Pythonic.
This also works:
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
_secondary: float | None = None
def __post_init__(self):
if self._secondary is None:
self.secondary = self.primary
else:
self.secondary = self._secondary
or this:
@dataclasses.dataclass
class RelatedValues:
primary: float
_: dataclasses.KW_ONLY
_secondary: float | None = None
@property
def secondary(self) -> float:
if self._secondary is None:
self.secondary = self.primary
else:
self.secondary = self._secondary
But the latter two are just mangling my kwargs for the sake of type narrowing, which kind of feels wrong.
What am I missing?
答案1
得分: 1
如果 secondary
总是被赋予一个非 None
的值,那么在一开始就不应该将其类型定义为 float | None
。实际上,只有作为 __init__
方法的 参数 传递进来的 secondary_
可能是 None
。
from dataclasses import dataclass, field, InitVar
@dataclass
class RelatedValues:
primary: float
secondary: float = field(init=False)
secondary_: InitVar[float|None] = None
def __post_init__(self, secondary_):
if secondary_ is None:
secondary_ = self.primary
self.secondary = secondary_
只有在你一开始不想提供自己的 __init__
方法时才需要上述步骤。例如,
@dataclass(init=False)
class RelatedValues:
primary: float
secondary: float
def __init__(self, primary: float, secondary: float = None):
if secondary is None:
secondary = primary
self.primary = primary
self.secondary = secondary
英文:
If secondary
will always be assigned a non-None
value, it should not be typed as float | None
in the first place. It's only the argument to __init__
, used to initialize self.secondary
, that might be None
.
from dataclasses import dataclass, field, InitVar
@dataclass
class RelatedValues:
primary: float
secondary: float = field(init=False)
secondary_: InitVar[float|None] = None
def __post_init__(self, secondary_):
if secondary_ is None:
secondary_ = self.primary
self.secondary = secondary_
These hoops are only necessary if you don't want to provide your own __init__
method in the first place. For example,
@dataclass(init=False)
class RelatedValues:
primary: float
secondary: float
def __init__(self, primary: float, secondary: float = None):
if secondary is None:
secondary = primary
self.primary = primary
self.secondary = secondary
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论