Guido:
> 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).
D'Aprano:
> I don't think it duck-types as an iterator. Here's an example:
>
> class A:
> def __init__(self): self.items = [1, 2, 3]
> def __next__(self):
> try: return self.items.pop()
> except IndexError: raise StopIteration
>
> >>> for item in A(): pass
> ...
> Traceback (most recent call last):
> File "<stdin>", line 1, in <module>
> TypeError: 'A' object is not iterable
Guido:
> Yes, we all understand that. The reason I invoked "duck typing" is that as
> long as you don't use the iterator in a situation where iter() is called
> on it, it works fine.
I'm confused.
- a "broken" iterator should be usable in `for`;
- `A` is a broken iterator;
but
- `A()` is not usable in `for`.
What am I missing?
Steven's class A is the kind of class a custom sequence might return from its __iter__ method. E.g.
class S:
def __iter__(self):
return A()
Now this works:
for x in S(): ...
However this doesn't:
for x in iter(S()): ...
In Steven's view, A does not deserve to work in the former case: Because A is a "broken" iterator, he seems to want it rejected by the iter() call that is *implicit* in the for-loop.
Reminder about how for-loops work:
This:
for x in seq:
<body>
translates (roughly) to this:
_it = iter(seq)
while True:
try:
x = next(_it)
except StopIteration:
break
<body>