[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Steven D'Aprano
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
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/3BQ2KIYFVRDKRK3HFLAFPS2GCBEAT24R/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Steven D'Aprano
On Wed, Sep 15, 2021 at 08:57:58AM -0700, Guido van Rossum wrote:

[...]
> 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. Just like a class with a readline() method works fine in
> some cases where a file is expected.

Okay, you've convinced me that perhaps duck typing is an appropriate 
term to use.

But I hope we wouldn't be arguing that a class with only a readline() 
method *is* a file object and changing the docs to support that view :-)


[...]
> No-one is arguing that an iterator that doesn't define __iter__ is great.

I'm arguing that it's not an iterator at all, even if you can use it in 
place of an iterator under some circumstances. As you pointed out, there 
is already a name for that: iterable.


> And the docs should continue to recommend strongly to add an __iter__
> method returning self.

Agreed. That's part of the iterator protocol.

If some objects don't need to support the full iterator protocol in 
order to get the job done, then that's great, and people should be 
allowed to support only the part of the protocol they need.


> My only beef is with over-zealous people who might preemptively want to
> reject an iterator at runtime that only has __next__; in particular "for"
> and iter() have no business checking for this attribute ("for" only needs
> __next__, and iter() only should check for the minimal version of the
> protocol to reject things without __next__).

Again, I agree. `for` and iter() should only check for the minimum of 
what they need.


> > I believe that iterable objects that define `__next__` but not
> > `__iter__` are fundamentally broken. If they happen to work in some
> > circumstances but not others, that's because the iterator protocol is
> > relaxed enough to work with broken iterators :-)
> >
> 
> Your opinion is loud and clear. I just happen to disagree.

I think we're in violent agreement here :-)

Obligatory Argument Sketch video:

https://www.youtube.com/watch?v=ohDB5gbtaEQ


-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/5PCJG3L725HTIANQDQRQAL2S6XE3IQM2/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Chris Barker via Python-Dev
Note: I am all for not enforcing anything here -- let's keep duck typing
alive!

If static type checkers want to be more pedantic, they can be -- that's
kinda what they are for :-)

But the OP wrote:

"""
 "[i]terators are required to have an __iter__()
 method"
which neither `for` nor `iter()` actually enforce.
"""

I'm confused -- as far as I can tell `for` does enforce this -- well, it
doesn't enforce it, but it does require it, which is the same thing, yes?
But does it need to?

On Wed, Sep 15, 2021 at 4:07 PM Guido van Rossum  wrote:

> Reminder about how for-loops work:
>
> This:
>
> for x in seq:
> 
>
> translates (roughly) to this:
>
> _it = iter(seq)
> while True:
> try:
> x = next(_it)
> except StopIteration:
> break
> 
>

exactly -- that call to iter is always made, yes?

The "trick" here is that we want it to be easy to use a for loop with
either an iterable or an iterator. Otherwise, we would require people to
write:

for i in iter(a_sequence):
...

which I doubt anyone would want, backward compatibility aside.

And since iter() is going to always get called, we need __iter__ methods
that return self.

However, I suppose one could do a for loop something like this instead.

_it = seq
while True:
try:
x = next(_it)
except TypeError:
_it = iter(_it)
x = next(_it)
except StopIteration:
break


That is, instead of making every iterator an iterable, keep the two
concepts more distinct:

An "Iterator" has a __next__ method that returns an item or raises
StopIteration.

An "Iterable" has an __iter__ method that returns an iterator.

That would mean that one couldn't write a single class that is both an
iterable and an iterator, and uses (abuses) __iter__ to reset itself. But
would that be a bad thing?

Anyway, this is just a mental exercise, I am not suggesting changing
anything.

-CHB

-- 

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR(206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115   (206) 526-6317   main reception

chris.bar...@noaa.gov
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/5OBJCQPV2A6MB7BNYUEFASU2P4D23BWQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Guido van Rossum
On Wed, Sep 15, 2021 at 3:54 PM Ethan Furman  wrote:

> 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 "", line 1, in 
>  > 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:


translates (roughly) to this:

_it = iter(seq)
while True:
try:
x = next(_it)
except StopIteration:
break


-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/HS5TCRWR2QABQCOCM5JDW4642KXWO7XR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Ethan Furman

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 "", line 1, in 
> 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?

--
~Ethan~
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/ZMDWM7ICFLD5R7URT2ME4WNYBVQZKNUT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Terry Reedy

On 9/15/2021 12:33 AM, Guido van Rossum wrote:
On Tue, Sep 14, 2021 at 9:03 PM Steven D'Aprano > 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



Like Steven, I consider 'iterators are iterables' to be a very positive 
feature.


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").


I agree with this also as I consider 'duck typing' (delayed type 
checking by use) and 'consenting adults' (break rules at one's own risk) 
to also be features. If iter were to check for __iter__ on the return 
object, it might as well call it to see if it returns the same object. 
That might be appropriate for a 'SargentPython' implementation, but, to 
me, not for CPython.


--
Terry Jan Reedy

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/DJPR23CY6N3GP6DDULPBMSHWH7JKWMFT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: python3.10rc2 compilation on android/termux/clang12.0.1 fails

2021-09-15 Thread Guido van Rossum
Sounds to me as if the first warning is somewhat legit (you can probably
ignore it).

The second seems to be a limitation of your platform -- that code is only
compiled if HAS_GETRANDOM is set by the configure script, so apparently
./configure determined that it exists, but the compiler thinks it doesn't.
Maybe it's in a different header file?

Please understand that your platform is not officially supported so we can
only provide limited hints.

On Wed, Sep 15, 2021 at 10:19 AM Sandeep Gupta 
wrote:

> I am trying to compile Python3.10rc2 on rather unusual platform (termux on
> android). The
> gcc version is listed below:
> ~ $ g++ -v
> clang version 12.0.1
> Target: aarch64-unknown-linux-android24
> Thread model: posix
> InstalledDir: /data/data/com.termux/files/usr/bin
>
> I get following warnings and errors:
> Python/pytime.c:398:10: warning: implicit conversion from 'long' to
> 'double' changes value from 9223372036854775807 to 9223372036854775808
> [-Wimplicit-const-int-float-conver
> sion]
>if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
>
> Python/bootstrap_hash.c:141:17: error: implicit declaration of function
> 'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
>n = getrandom(dest, n, flags);
>^
> Python/bootstrap_hash.c:145:17: error: implicit declaration of function
> 'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
>n = getrandom(dest, n, flags);
>
> Not sure if this is limitation of the platform or Python codebase needs
> fixes.
>
> Thanks
> -S ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/KEURSMCLUVI7VPKM6M2VUV4JIW6FP66Z/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/DY2FUDB4UVL7J3V2ZTL7UHS5SUW5N7QU/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: python3.10rc2 compilation on android/termux/clang12.0.1 fails

2021-09-15 Thread Jelle Zijlstra
Did previous versions of Python compile successfully? The RC phase wouldn't
be the right time to add support for a new platform.

El mié, 15 sept 2021 a las 10:15, Sandeep Gupta ()
escribió:

> I am trying to compile Python3.10rc2 on rather unusual platform (termux on
> android). The
> gcc version is listed below:
> ~ $ g++ -v
> clang version 12.0.1
> Target: aarch64-unknown-linux-android24
> Thread model: posix
> InstalledDir: /data/data/com.termux/files/usr/bin
>
> I get following warnings and errors:
> Python/pytime.c:398:10: warning: implicit conversion from 'long' to
> 'double' changes value from 9223372036854775807 to 9223372036854775808
> [-Wimplicit-const-int-float-conver
> sion]
>if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {
>
> Python/bootstrap_hash.c:141:17: error: implicit declaration of function
> 'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
>n = getrandom(dest, n, flags);
>^
> Python/bootstrap_hash.c:145:17: error: implicit declaration of function
> 'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
>n = getrandom(dest, n, flags);
>
> Not sure if this is limitation of the platform or Python codebase needs
> fixes.
>
> Thanks
> -S ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/KEURSMCLUVI7VPKM6M2VUV4JIW6FP66Z/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/G6LCSHQBTPR3HUPUNTCANXYPW4K34TFQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] python3.10rc2 compilation on android/termux/clang12.0.1 fails

2021-09-15 Thread Sandeep Gupta
I am trying to compile Python3.10rc2 on rather unusual platform (termux on
android). The
gcc version is listed below:
~ $ g++ -v
clang version 12.0.1
Target: aarch64-unknown-linux-android24
Thread model: posix
InstalledDir: /data/data/com.termux/files/usr/bin

I get following warnings and errors:
Python/pytime.c:398:10: warning: implicit conversion from 'long' to
'double' changes value from 9223372036854775807 to 9223372036854775808
[-Wimplicit-const-int-float-conver
sion]
   if (!_Py_InIntegralTypeRange(_PyTime_t, d)) {

Python/bootstrap_hash.c:141:17: error: implicit declaration of function
'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
   n = getrandom(dest, n, flags);
   ^
Python/bootstrap_hash.c:145:17: error: implicit declaration of function
'getrandom' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
   n = getrandom(dest, n, flags);

Not sure if this is limitation of the platform or Python codebase needs
fixes.

Thanks
-S
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KEURSMCLUVI7VPKM6M2VUV4JIW6FP66Z/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Guido van Rossum
On Tue, Sep 14, 2021 at 11:44 PM Steven D'Aprano 
wrote:

> On Tue, Sep 14, 2021 at 09:38:38PM -0700, Guido van Rossum wrote:
>
> > > 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).
>
> 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
>
>
> class B:
> def __iter__(self):
> return A()
>
>
> It's fine to iterate over B() directly, but you can't iterate over
> A() at all. If you try, you get a TypeError:
>
> >>> for item in A():  pass
> ...
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: 'A' object is not iterable
>

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. Just like a class with a readline() method works fine in
some cases where a file is expected.


> In practice, this impacts some very common techniques. For instance,
> pre-calling iter() on your input.
>
>
> >>> x = B()
> >>> it = iter(x)
> >>> for value in it:  pass
> ...
> Traceback (most recent call last):
>   File "", line 1, in 
> TypeError: 'A' object is not iterable
>
>
> There are all sorts of reasons why one might pre-call iter(). One common
> one is to pre-process the first element:
>
> it = iter(obj)
> first = next(obj, None)
> for item in it: ...
>
> Another is to test for an iterable. iter(obj) will raise TypeError if
> obj is not a sequence, collection, iterator, iterable etc.
>
> Another is to break out of one loop and then run another:
>
> it = iter(obj)
> for x in it:
> if condition: break
> do_something()
>
> for x in it:
> something_else()
>
>
> I'm sure there are others I haven't thought of.
>

No-one is arguing that an iterator that doesn't define __iter__ is great.
And the docs should continue to recommend strongly to add an __iter__
method returning self.

My only beef is with over-zealous people who might preemptively want to
reject an iterator at runtime that only has __next__; in particular "for"
and iter() have no business checking for this attribute ("for" only needs
__next__, and iter() only should check for the minimal version of the
protocol to reject things without __next__).


> I believe that iterable objects that define `__next__` but not
> `__iter__` are fundamentally broken. If they happen to work in some
> circumstances but not others, that's because the iterator protocol is
> relaxed enough to work with broken iterators :-)
>

Your opinion is loud and clear. I just happen to disagree.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/H7XPX4VRUZGZ2ZHPYU6YFKKI6YLD73MP/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Steven D'Aprano
On Tue, Sep 14, 2021 at 04:50:05PM -0700, Guido van Rossum wrote:

> TBH I don't think there is an *actual* problem here. I think it's just
> about choosing the right wording for the glossary (which IMO does not have
> status as a source of truth anyway).

+1


-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/BIY52VZAIX7LE5CYNBLZDORJJ6II6MGL/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Should the definition of an "(async) iterator" include __iter__?

2021-09-15 Thread Steven D'Aprano
On Tue, Sep 14, 2021 at 09:38:38PM -0700, Guido van Rossum wrote:

> > 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).

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
 

class B:
def __iter__(self):
return A()


It's fine to iterate over B() directly, but you can't iterate over 
A() at all. If you try, you get a TypeError:

>>> for item in A():  pass
... 
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'A' object is not iterable


In practice, this impacts some very common techniques. For instance, 
pre-calling iter() on your input.


>>> x = B()
>>> it = iter(x)
>>> for value in it:  pass
... 
Traceback (most recent call last):
  File "", line 1, in 
TypeError: 'A' object is not iterable


There are all sorts of reasons why one might pre-call iter(). One common 
one is to pre-process the first element:

it = iter(obj)
first = next(obj, None)
for item in it: ...

Another is to test for an iterable. iter(obj) will raise TypeError if 
obj is not a sequence, collection, iterator, iterable etc.

Another is to break out of one loop and then run another:

it = iter(obj)
for x in it:
if condition: break
do_something()

for x in it:
something_else()


I'm sure there are others I haven't thought of.


I believe that iterable objects that define `__next__` but not 
`__iter__` are fundamentally broken. If they happen to work in some 
circumstances but not others, that's because the iterator protocol is 
relaxed enough to work with broken iterators :-)



-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/54WUEDKDIT7FXH3JHL34VZDJCFV5Q3FH/
Code of Conduct: http://python.org/psf/codeofconduct/