On Tue, Sep 14, 2021 at 9:31 PM Steven D'Aprano <steve@pearwood.info> wrote:
If it helps, I have tons of code that tests for iterators using:

    iter(obj) is obj

That has been a documented requirement for the iterator protocol
forever. Its in the PEP.

"A class that wants to be an iterator should implement two methods: a
next() method that behaves as described above, and an __iter__() method
that returns self."

https://www.python.org/dev/peps/pep-0234/

However, the description clarifies that the reason for requiring __iter__ is weaker than the reason for requiring __next__.
 
We have objects such that:

    iter(obj)

returns an iterator, but aren't themselves iterators.

Yeah, those are Iterables.
 
The most common
example of that would be, I think, classes that define __iter__ as a
generator method:

    class A:
        def __iter__(self):
            for x in range(10):
                yield x

Then we have actual iterators, like iter(A()). They define `__iter__`
that returns self.

I don't know what I would call an object that only has __next__,
apart from "broken" :-(

It's still an iterator, since it duck-types in most cases where an iterator is required (notably "for", which is the primary use case for the iteration protocols -- it's in the first sentence of PEP 234's abstract).

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