
On Mon, Nov 29, 2021, 12:33 AM Paul Bryan <pbryan@anode.ca> wrote:
1. Noted: Python's for statement will happily iterate over an object that only implements __next__. 2. The documentation is pretty clear on what is expected of an iterator: implement __next__ *and* __iter__. 3. It is perfectly reasonable for __iter__ to return something other than self; the documentation already reflects this. 4. If you believe the documentation is in error or the requirement should be relaxed, then further discussion is probably warranted.
Not so much "in error" as "could be clarified." Another couple words like "usually desirable" ... for an iterator to implement .__iter__() would cover it. Maybe I'll make a PR on the docs. I agree that an iterator that doesn't implement .__iter__() is usually unnecessarily a PITA. Especially since "return self" is *usually* a perfectly good implementation.
On Mon, 2021-11-29 at 00:22 -0500, David Mertz, Ph.D. wrote:
On Mon, Nov 29, 2021, 12:16 AM Paul Bryan <pbryan@anode.ca> wrote:
And the second link?
Same comments, basically. But the more germane thing is that even assuming a class has both .__next__() and .__iter__(), it is perfectly reasonable for the latter to return something other than `self`.
The Foo and Bar classes are slightly contrived, but I've written production code where e.g. `iter(thing)` returns a new `thing.__class__` instance rather than self.
On Mon, 2021-11-29 at 00:11 -0500, David Mertz, Ph.D. wrote: If you
On Sun, Nov 28, 2021, 11:43 PM Paul Bryan <pbryan@anode.ca> wrote:
According to https://docs.python.org/3/glossary.html#term-iterator and https://docs.python.org/3/library/stdtypes.html#typeiter, iterators must implement the __iter__ method.
From your first link:
CPython implementation detail: CPython does not consistently apply the requirement that an iterator define __iter__().
That said, I don't think the description at the link is very good. Anyway, it's different from what I teach, and also different from how Python actually behaves. E.g.:
class Foo: ... def __iter__(self): ... return Bar() ... class Bar: ... def __next__(self): ... if random() > 0.5: ... raise StopIteration ... return "Bar" ... for x in Foo(): ... print(x) ... Bar Bar Bar
Or anyway, what would you call `bar := Bar()` if not "an iterator?!
On Sun, 2021-11-28 at 22:02 -0500, David Mertz, Ph.D. wrote:
On Sun, Nov 28, 2021, 8:59 PM Steven D'Aprano
To be an iterator, your object needs:
1. a `__next__` method which returns the next value; 2. and an `__iter__` method which returns self.
That's not quite right.
An iterator only needs .__next__(), and an iterable only needs .__iter__(). Returning self is a convenient, and probably the most common, way of creating an object that is both. But exceptions exist, and remain iterators and/or iterables.