В чем разница между итераторами Mypy и генераторами? - PullRequest
0 голосов
/ 11 июня 2019

Каковы основные различия и что и где следует использовать каждый?

Например, в этом примере использование обоих - и Iterator, и Generator кажется мне подходящим ... но верно ли это?

Iterator

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 голосов
/ 11 июня 2019

Всякий раз, когда вы не уверены, что именно является каким-то встроенным типом, я рекомендую проверить Typeshed , хранилище подсказок типов для стандартной библиотеки Python (и некоторых избранных сторонних модулей).Mypy выпекается в версии с типами с каждым выпуском.

Например, вот определения того, что именно итератор и генератор:

@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.

Это то, для чего на самом деле нужны два других параметра типа - когда вы делаете Generator[A, B, C], вы утверждаете, что получаемые вами значения имеют тип A, значения, которые вы отправляете в генератор:типа B, а значение, возвращаемое генератором, имеет тип C.

Вот некоторые дополнительные полезные материалы для чтения:

  1. Назначение функции "Отправить" генератора python?
  2. Разница между генераторами Python иИтераторы
  3. Возврат в генератор вместе с yield в Python 3.3
  4. https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/

Итак, когда следуетвы используете Iterator vs Generator?

Ну, в общем, вам следует склоняться к использованию типа, который помогает вызывающей стороне понять, как вы ожидаете, что будет использоваться возвращаемое значение.

Например, возьмитеfib пример.Все, что вы делаете, - это значения выходных данных: поток информации является односторонним, и код на самом деле не настроен на прием информации от вызывающей стороны.

Таким образом, было бы наиболее понятным использовать вместо этого IteratorGenerator в этом случае: Iterator лучше всего отражает одностороннюю природу вашей реализации FIB.

(И если бы вы написали генератор, в котором поток данных должен быть двунаправленным, вы, конечно, нужно , чтобы использовать Generator вместо Iterator.)

...