【问题标题】:How to annotate a custom types __iter__ to correctly indicate non-uniform returned types?如何注释自定义类型 __iter__ 以正确指示非统一返回类型?
【发布时间】:2023-02-14 11:32:52
【问题描述】:

我有一个自定义类型,我想为其启用解包它的值(元组解包等)。我知道在 Python 中执行此操作的最简单方法是实现 __iter__。这在运行时效果很好,但我想提供类型注释,以便为每个项目返回正确的类型,例如:

import typing as t
from dataclasses import dataclass

@dataclass
class Foo:
    a: str
    b: bool

    def __iter__(self) -> t.Iterable[str, bool]:
        yield self.a
        yield self.b

在运行时,这按预期工作:


string, bool = Foo("Hello", False)

但是,上面的stringbool被报告为Any类型。有没有一种合理的方法来提供这个用例同时保留类型?

现实世界的类型不容易转换为 NamedTuple 等。

类似于How to annotate types of multiple return values?

【问题讨论】:

  • 运行时不关心类型提示。但是你的提示并没有说它是一个迭代器,它产生一个字符串,然后是一个布尔值,然后停止。 (我不确定它是什么说;也许是一个以任何顺序产生字符串和/或布尔值的 Iterable。)
  • 您必须使用某种联合,并且在您解压它时它不会推断构成类型
  • mypy拒绝Iterable[str, bool]: '错误:“可迭代”需要 1 个类型参数,但给出了 2 个'。
  • Iterable[T] 值表示其 __next__ 方法具有返回类型 T 的迭代器。不过,您似乎想要的是一个返回类型为 __next__ 的方法变化当它被调用时,这不是您可以静态指定的东西。
  • 我认为你能做的最好的是:-> t.Iterator[Union[str,int]]

标签: python mypy python-typing


【解决方案1】:

您想要的功能非常特定于 tuple 内置,并且通过 mypy 和其他类型检查器中的特殊外壳支持。然而,你可以调整类型检查器让它认为你的类实际上是一个元组子类,所以它在解包时会得到类似的处理。

以下作品(playground):

import typing as t
from dataclasses import dataclass


if t.TYPE_CHECKING:
    base = tuple[str, bool]
else:
    base = object

@dataclass
class Foo(base):
    a: str
    b: bool
    
    def __iter__(self) -> t.Iterator[str | bool]:
        yield self.a
        yield self.b


p, q = Foo('a', True)
reveal_type(p)
reveal_type(q)

typing.TYPE_CHECKING 是一个特殊常量,它在运行时是False(所以里面的代码不会被执行),但是对于类型检查器来说是True

【讨论】:

  • 棒极了!正如您所说,这可能不是产品代码的好主意。
猜你喜欢
  • 2016-09-10
  • 2020-09-20
  • 2019-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-03
  • 1970-01-01
相关资源
最近更新 更多