将生成器函数注释为迭代器的混淆

Dav*_*ang 6 python type-hinting mypy

在 python类型文档中它是这样写的:

或者,将您的生成器注释为具有 Iterable[YieldType] 或 Iterator[YieldType] 的返回类型:

def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1
Run Code Online (Sandbox Code Playgroud)

我写了一个打印无限流的非常简单的例子。我有一个生成器函数,它被传递给另一个函数然后被调用。

from typing import Iterator


def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1


def print_infinite_stream(inf_iterator: Iterator[int]):
    for x in inf_iterator(5):
        print(x)


print_infinite_stream(infinite_stream)
Run Code Online (Sandbox Code Playgroud)

使用 mypy 我得到两个错误:

  • 错误:迭代器 [int] 不可调用

  • 错误:“print_infinite_stream”的参数 1 具有不兼容的类型“Callable[[int], Iterator[int]]”;预期“迭代器[int]”

我很困惑为什么我根据文档工作并安装了最新的 python (3.6.5) 和 mypy (0.590) 时出现这些错误。这里有什么问题?

eth*_*nhs 7

将您的生成器注释为具有 Iterable[YieldType] 或 Iterator[YieldType] 的返回类型

生成器函数返回生成器,它们本身不是生成器。如果你这样做:

reveal_type(infinite_stream),你会得到类似的东西Callable[[int], Iterator[int]]

您想要的是函数的返回值,即实际的迭代器。

from typing import Iterator


def infinite_stream(start: int) -> Iterator[int]:
    while True:
        yield start
        start += 1


def print_infinite_stream(inf_iterator: Iterator[int]):
    for x in inf_iterator:
        print(x)


print_infinite_stream(infinite_stream(5))
Run Code Online (Sandbox Code Playgroud)

这更有意义,因为现在可以print_infinite_stream处理任何迭代器,而不仅仅是您的生成器函数。如果你reveal_type(infinite_stream(5))应该得到类似的东西Iterator[int],这正是你想要的。