【发布时间】:2021-11-09 22:56:39
【问题描述】:
假设我有一个对象,它是一个类的实例,如下所示:
@dataclass
class Foo:
bar: int
baz: str
为方便起见,我使用dataclasses,但在这个问题的上下文中,不要求类是dataclass。
通常,如果我想解包这样一个对象的属性,我必须实现__iter__,例如如下:
class Foo:
...
def __iter__(self) -> Iterator[Any]:
return iter(dataclasses.astuple(self))
bar, baz = Foo(1, "qux")
但是,从像pyright 这样的静态类型检查器的角度来看,我现在丢失了bar 和baz 的任何类型信息,它只能推断出类型为Any。我可以通过手动创建 iter 元组参数来稍微改进:
def __iter__(self) -> Iterator[Union[str, int]]:
return iter((self.bar, self.baz))
但我仍然没有bar 和baz 的特定类型。我可以注释bar和baz然后直接使用dataclasses.astuple如下:
bar: str
baz: int
bar, baz = dataclasses.astuple(Foo(1, "qux"))
但这需要可读性较差的多级列表理解,例如
bars: list[int] = [
bar for bar, _ in [dataclasses.astuple(foo) for foo in [(Foo(1, "qux"))]]
]
还将我与dataclasses联系起来。
显然,这一切都不是不可克服的。如果我想使用类型检查器,我可以不使用 unpack 语法,但如果有一种干净的方法可以做到这一点,我真的很想这样做。
如果当前无法使用通用方法,则可以接受特定于 dataclasses 或更好的是 attrs 的答案。
【问题讨论】:
-
另一种方法是编写一个定制方法
astuple,它返回一个您正确注释的Tuple[x,y],然后使用bar, baz = Foo.astuple() -
@juanpa.arrivillaga 这比
dataclasses.astuple或其他等价物略好,是的,但我希望有一个我不知道的类似dunder方法的技巧来使解包语法起作用裸露的物体。这可能是目前不可能的,因为解包必须使用__iter__并且当有多个包含类型时,__iter__必须返回Iterator[Union]类型。如果您可以通过文档来源确认这一点,那将是一个可以接受的答案。我一直无法这样做,因此提出了这个问题。 -
是的,它基本上就是这样工作的。文档中没有直接说明这一点,但它隐含在使用 iteration 的 iterable unpacking 的定义中。
-
所以,这里是赋值语句的文档:docs.python.org/3/reference/simple_stmts.html 相关部分在“else”要点中:
标签: python python-typing iterable-unpacking pyright