Mypy迭代器和生成器有什么区别?

时间:2019-06-11 13:24:53

标签: python-3.x types mypy

主要区别是什么?分别应在什么地方使用?

例如,在此示例中,同时使用-和Iterator和Generator似乎对我来说很合适……但这是真的吗?

迭代器

from typing import Generator, Iterator

def fib(n: int) -> Iterator[int]:
    a :int = 0
    b :int = 1
    while a < n:
        yield a
        a, b = b, a+b

print([x for x in fib(3)])

生成器

from typing import Generator 

def fib(n: int) -> Generator[int, None, None]:
    a :int = 0
    b :int = 1
    while a < n:
        yield a
        a, b = b, a+b

print([x for x in fib(3)])

1 个答案:

答案 0 :(得分:0)

无论何时不确定确切的内置类型是什么,我建议检查Typeshed,这是Python标准库的类型提示存储库(以及某些精选的3rd party模块)。 Mypy会在每个发行版中烘烤一个版本。

例如,here are the definitions到底是什么迭代器和生成器:

@runtime
class Iterator(Iterable[_T_co], Protocol[_T_co]):
    @abstractmethod
    def __next__(self) -> _T_co: ...
    def __iter__(self) -> Iterator[_T_co]: ...

class Generator(Iterator[_T_co], Generic[_T_co, _T_contra, _V_co]):
    @abstractmethod
    def __next__(self) -> _T_co: ...

    @abstractmethod
    def send(self, value: _T_contra) -> _T_co: ...

    @abstractmethod
    def throw(self, typ: Type[BaseException], val: Optional[BaseException] = ...,
              tb: Optional[TracebackType] = ...) -> _T_co: ...

    @abstractmethod
    def close(self) -> None: ...

    @abstractmethod
    def __iter__(self) -> Generator[_T_co, _T_contra, _V_co]: ...

    @property
    def gi_code(self) -> CodeType: ...
    @property
    def gi_frame(self) -> FrameType: ...
    @property
    def gi_running(self) -> bool: ...
    @property
    def gi_yieldfrom(self) -> Optional[Generator]: ...

注意:

  1. 迭代器只有两种方法:__next____iter__,但是生成器还有更多方法。
  2. 生成器是迭代器的子类型-每个生成器也是一个迭代器,但反之亦然。

但这在高层次上意味着什么?

简而言之,使用迭代器,信息流只是单向。当拥有迭代器时,您实际上可以调用__next__方法来获取要产生的下一个值。

相反,生成器的信息流是双向的 :您可以通过send方法将信息 back 发送到生成器中。

这实际上是其他两个类型参数的用途-当您执行Generator[A, B, C]时,您表示产生的值是A类型,即您发送到生成器中的值的类型为B,而您从生成器返回的值的类型为C

还有一些其他有用的阅读材料:

  1. python generator "send" function purpose?
  2. Difference between Python's Generators and Iterators
  3. Return in generator together with yield in Python 3.3
  4. https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/

那么,什么时候应该使用Iterator vs Generator?

通常,您应该偏向使用有助于调用者理解您期望如何使用返回值的类型。

例如,以您的fib为例。您要做的所有事情都是产生值:信息流是单向的,并且代码并未真正设置为接受来自调用方的信息。

因此,在这种情况下,使用Iterator而不是Generator是最可理解的:Iterator最好地反映了fib实现的单向性。

(如果您编写的生成器的数据流是双向的,那么当然需要使用Generator而不是Iterator。)