我对 Pylance(VS Code 的静态类型检查器,基于 Pyright)相对较新,并且刚刚使用
count()
无限迭代器偶然发现了此类型检查错误。我有一些代码一直在使用,我将其简化为以下重现问题的基本版本:
from itertools import count
def foo() -> int:
for i in count():
if i == 42:
return i
print(foo())
我在
count()
上使用这个循环本质上是 while True
的变体,在我等待满足条件时为我管理索引。鉴于它是一个无限循环,该函数的唯一代码路径是通过循环内返回 int 的条件,但 Pylance/Pyright 给了我以下类型错误:
声明返回类型为“int”的函数必须在所有代码路径上返回值
类型“None”无法分配给类型“int”Pylance(reportGeneralTypeIssues)
我发现可以通过以下任一方式来消除该问题:
# type: ignore
抑制警告,这可能会吞掉不相关的问题。Optional[int]
,这是完全错误的。return -1
(或任何假值),这可以工作,但会添加令人困惑的无操作额外行。def foo() -> int:
i = 0
while True:
if i == 42:
return i
i += 1
但我想知道这里是否有一个更干净的解决方案可以以某种方式正确地将这个循环标记为无限。
我也希望了解其原因 - 这只是 Pylance/Pyright 错误(缺少功能),还是将
count()
标记为无限迭代器是否存在更深层次的技术限制?
类型系统不知道生成器是否是无限的。
mypy
中有一个与此相关的问题 (#7374),但它是在 2019 年创建的,并且被标记为低优先级。
还有问题#5992,Guido van Rossum(是的,Python 的创建者本人)评论如下:
老实说,这样的代码似乎很少见,除了这样的玩具示例之外,人类也很难分析。代码中不可到达点的约定是
(mypy 似乎可以理解)。assert False
所以我会采用在循环后添加
assert False
的方法。或者你也可以这样做(在#5992中提到):
from itertools import count
def foo() -> int:
while True:
for i in count():
if i == 42:
return i