On Tue, Sep 14, 2021 at 9:03 PM Steven D'Aprano <steve@pearwood.info> wrote:
On Tue, Sep 14, 2021 at 12:33:32PM -0700, Guido van Rossum wrote:
> My view of this is:
>
> A. It's not an iterator if it doesn't define `__next__`.
>
> B. It is strongly recommended that iterators also define `__iter__`.
>
> In "standards" language, I think (A) is MUST and (B) is merely OUGHT or
> maybe SHOULD.

That's not what the docs say :-)

https://docs.python.org/3/library/stdtypes.html#iterator-types

Huh, so it does. And in very clear words as well. I still don't think this should be enforced by checks for the presence of __iter__ in situations where it's not going to be called (e.g. in iter() itself and in "for x in it"). But since this is a longstanding convention and matches collections.abc.Iterator (and typing.Iterator) we might as well *document* it to be the case.
 
Part of the problem is that there are two kinds of thing that we call
"iterator":

1. Objects that we implicitly or explicitly pass to `iter()` in order to
return an interator object; they only need to define an `__iter__`
method that returns the actual iterator object itself.

No, we don't call that an iterator. That's an *Iterable*. In this the docs you point to are actually weak:

- It doesn't use the term Iterable at all but describe it as "container objects" or "containers".

- It says " Sequences, described below in more detail, always support the iteration methods." That's wrong, or at the very least misleading, since a sequence itself *only* supports __iter__ -- it's the Iterator returned by s.__iter__() that supports __next__.
 
(That's a slight simplification, because iter() will fall back on the
Sequence Protocol if `__iter__` isn't defined. But to my mind, that
makes Sequence Protocol objects *iterables* not iterators.)

Right, it's wrong.
 
2. Iterator objects themselves, which are defined by a protocol, not a
type. The iterator object MUST define both `__iter__` and `__next__`,
and the `__iter__` method MUST return self.

So you say. I will compromise and agree that Iterators MUST have __next__ and SHOULD have __iter__ returning self. The distinction is that without __next__ it's not an Iterator. But without __iter__ it's merely a broken Iterator (that nevertheless works in most situations).

--
--Guido van Rossum (python.org/~guido)