Всякий раз, когда вы не уверены, что именно является каким-то встроенным типом, я рекомендую проверить 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]: ...
Уведомлениечто:
- Итераторы имеют только два метода:
__next__
и __iter__
, но у генераторов гораздо больше. - Генераторы - это подтип Итераторов -каждый генератор также является итератором, но не наоборот.
Но что это значит на высоком уровне?
Короче говоря, с итераторами потокинформация только в одну сторону .Когда у вас есть итератор, все, что вы действительно можете сделать, это вызвать метод __next__
, чтобы получить следующее значение, которое будет получено.
Напротив, поток информации с генераторами равен двунаправленный : вы можете отправить информацию обратно в генератор с помощью метода send
.
Это то, для чего на самом деле нужны два других параметра типа - когда вы делаете Generator[A, B, C]
, вы утверждаете, что получаемые вами значения имеют тип A
, значения, которые вы отправляете в генератор:типа B
, а значение, возвращаемое генератором, имеет тип C
.
Вот некоторые дополнительные полезные материалы для чтения:
- Назначение функции "Отправить" генератора python?
- Разница между генераторами Python иИтераторы
- Возврат в генератор вместе с yield в Python 3.3
- https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
Итак, когда следуетвы используете Iterator vs Generator?
Ну, в общем, вам следует склоняться к использованию типа, который помогает вызывающей стороне понять, как вы ожидаете, что будет использоваться возвращаемое значение.
Например, возьмитеfib
пример.Все, что вы делаете, - это значения выходных данных: поток информации является односторонним, и код на самом деле не настроен на прием информации от вызывающей стороны.
Таким образом, было бы наиболее понятным использовать вместо этого IteratorGenerator в этом случае: Iterator лучше всего отражает одностороннюю природу вашей реализации FIB.
(И если бы вы написали генератор, в котором поток данных должен быть двунаправленным, вы, конечно, нужно , чтобы использовать Generator вместо Iterator.)