On Wed, Sep 15, 2021 at 04:01:31PM -0700, Guido van Rossum wrote:
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()
Correct, where A itself has a `__next__` method but no `__iter__` method.
Now this works:
for x in S(): ...
Agreed.
However this doesn't:
for x in iter(S()): ...
Correct, but *in practice* nobody would actually write it like that, since that would be silly. But what can happen is that one might have earlier called iter() directly, and only afterwards used the result in a for loop. it = iter(S()) # assert isinstance(it, A) ... for x in it: ... Or we can short-cut the discussion and just write it like this: for x in A(): ... which clearly fails because A has no `__iter__` method. When we write it like that, it is clear that A is not an iterator. The waters are only muddied because *most of the time* we don't write it like that, we do the simplest thing that can work: for x in S(): ... which does work. So the question is, in that last snippet, the version that *does* work, what are we iterating over? Are we iterating over S() or A()? I think the answer is Yes :-)
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.
No, I'm not arguing that. 1. It's not a matter of "deserves", it is that A instances cannot be used *directly* in a for loop, because they have no `__iter__` method. 2. I don't want iter() or the for loop to reject *S* instances just because A instances don't have `__iter__`. 3. I don't need to propose that for loops reject A instances, since they already do that. That's the status quo, and it's working correctly according to the iterator protocol. The bottom line here is that I'm not asking for any runtime changes here at all. Perhaps improving the docs would be a good thing, and honestly I'm unsure what typeshed should do. I suppose that depends on whether you see the role of static type checking to be as strict as possible or as forgiving as possible. If you want your type checking to be strict, then maybe you want it to flag A as not an iterator. If you want it to accept anything that works, maybe you want it to allow S as an iterator. On the typeshed issue, Akuli comments that they have a policy of preferring false negatives. So I think that nothing needs to be done? https://github.com/python/typeshed/issues/6030#issuecomment-918544344 -- Steve