[Python-Dev] Re: PEP 467 feedback from the Steering Council

2021-09-14 Thread Baptiste Carvello
Le 13/09/2021 à 19:01, Barry Warsaw a écrit :
> There is some discussion going on in bpo-45155 about what the default value 
> of the `byteorder` argument should be for int.to_bytes() and int.from_bytes():

Hello,

a use case and feature request:

I have used int.to_bytes() and int.from_bytes() interactively at the
Python REPL for picking apart pieces of binary data files, in contexts
of debugging or casual reverse-engineering (I could have used `struct`,
but then I would have needed to reread the doc ;-)

For this use case, setting defaults for the arguments is obviously
beneficial (less typing), and the most comfortable defaults would be:

- for `length`, the minimum length needed to encode the integer (I
mostly care for the content, not the leading or trailing zeros);

- for `byteorder`, preferably a fixed default so I can remember it once
and for all, and in any case something rather than None (if the bytes
are reversed, I'll still recognize them).

Whatever comes out of this discussion, it would be nice if the
`byteorder` constants got a one-character short form, be it 'l' and 'b'
for discoverability, or '<' and '>' for consistency with `struct`.
Having to type 'little' is painfully long at the REPL.

Cheers,
Baptiste
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/7ZTUJDMSJEBLORSTHV6X6DZVESIKOKKL/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Brett Cannon
Over in https://github.com/python/typeshed/issues/6030 I have managed to
kick up a discussion over what exactly an "iterator" is. If you look at
https://docs.python.org/3/library/functions.html#iter you will see the docs
say it "Return[s] an iterator
 object." Great, but
you go the glossary definition of "iterator" at
https://docs.python.org/3/glossary.html#term-iterator you will see it says
"[i]terators are required to have an __iter__()

method" which neither `for` nor `iter()` actually enforce.

Is there something to do here? Do we loosen the definition of "iterator" to
say they *should* define __iter__? Leave it as-is with an understanding
that we know that it's technically inaccurate for iter() but that we want
to encourage people to define __iter__? I'm assuming people don't want to
change `for` and `iter()` to start requiring __iter__ be defined if we
decided to go down the "remove the __aiter__ requirement" from aiter() last
week.

BTW all of this applies to async iterators as well.
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/3W7TDX5KNVQVGT5CUHBK33M7VNTP25DZ/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Guido van Rossum
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.

On Tue, Sep 14, 2021 at 12:30 PM Brett Cannon  wrote:

> Over in https://github.com/python/typeshed/issues/6030 I have managed to
> kick up a discussion over what exactly an "iterator" is. If you look at
> https://docs.python.org/3/library/functions.html#iter you will see the
> docs say it "Return[s] an iterator
>  object." Great,
> but you go the glossary definition of "iterator" at
> https://docs.python.org/3/glossary.html#term-iterator you will see it
> says "[i]terators are required to have an __iter__()
> 
> method" which neither `for` nor `iter()` actually enforce.
>
> Is there something to do here? Do we loosen the definition of "iterator"
> to say they *should* define __iter__? Leave it as-is with an
> understanding that we know that it's technically inaccurate for iter() but
> that we want to encourage people to define __iter__? I'm assuming people
> don't want to change `for` and `iter()` to start requiring __iter__ be
> defined if we decided to go down the "remove the __aiter__ requirement"
> from aiter() last week.
>
> BTW all of this applies to async iterators as well.
> ___
> Python-Dev mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/[email protected]/message/3W7TDX5KNVQVGT5CUHBK33M7VNTP25DZ/
> 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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/OICGRBPLXO6WXO4CHTGUK46WIHO7PDUU/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Patrick Reader
I think there is also a distinction about the *current* meaning of "required" 
to be made, in "[i]terators are required to have an |__iter__()| 
 method": 
"required" doesn't specify whether this is:

1. by convention, and doing otherwise is just some form of undefined behaviour; 
for a human (or perhaps type-checker) reading it to think it's an iterator, it 
needs `__iter__`, but it's really something like passing an object of the wrong 
type to an unbound method - unenforced by the language (it used to be illegal 
in Py2)

2. in some way actually enforced: the iterator is required to have `__iter__` 
that returns self, and

While 1 is clearly what actually happens in CPython, was that the intended 
meaning? I'd think so - 1 is still a perfectly acceptable interpretation of 
"required" (even if "required" isn't the most clear way of expressing it). Even 
if it wasn't the original meaning, that's how I think it should now be 
interpreted because that's what it is de facto.

Do we know who originally wrote that line, so we could ask them? (The furthest 
I've traced it is 
https://github.com/python/cpython/commit/f10aa9825e49e8652f30bc6d92c736fe47bb134c
 but I don't have any knowledge of SVN or CVS (whichever was used at the time) 
to go further.)

Also, any user-defined iterator that doesn't also define __iter__ would be 
considered wrong and nobody would refuse to fix that. If it's already a bug 
anyway, why bother changing the behaviour and check that?

> 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.
>
> On Tue, Sep 14, 2021 at 12:30 PM Brett Cannon  > wrote:
>
> Over in https://github.com/python/typeshed/issues/6030 
>  I have managed to kick up a 
> discussion over what exactly an "iterator" is. If you look at 
> https://docs.python.org/3/library/functions.html#iter 
>  you will see the docs 
> say it "Return[s] an iterator 
>  object." Great, but 
> you go the glossary definition of "iterator" at 
> https://docs.python.org/3/glossary.html#term-iterator 
>  you will see it says 
> "[i]terators are required to have an |__iter__()| 
>  method" 
> which neither `for` nor `iter()` actually enforce.
>
> Is there something to do here? Do we loosen the definition of "iterator" 
> to say they /should/ define __iter__? Leave it as-is with an understanding 
> that we know that it's technically inaccurate for iter() but that we want to 
> encourage people to define __iter__? I'm assuming people don't want to change 
> `for` and `iter()` to start requiring __iter__ be defined if we decided to go 
> down the "remove the __aiter__ requirement" from aiter() last week.
>
> BTW all of this applies to async iterators as well.
>
Patrick
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/4EN4AUUYP2LQNTXI7CV5TJ2O33FJZVHK/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Brandt Bucher
I think it's also worth noting that a missing "`__iter__` that returns self" is 
trivial to recover from... just use a new reference to the iterator instead. 
The overhead of a method call for this convention almost seems silly.

What worries me most about changing the current "requirement" is that it may 
create either confusion or backward compatibility issues for 
`collections.abc.Iterator` (which is a subtype of `Iterable`, and thus requires 
`__iter__`).
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/RSV6MOIBVNEFKL4NDHTKDVSGVABVY65Q/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Guido van Rossum
On Tue, Sep 14, 2021 at 3:49 PM Brandt Bucher 
wrote:

> I think it's also worth noting that a missing "`__iter__` that returns
> self" is trivial to recover from... just use a new reference to the
> iterator instead. The overhead of a method call for this convention almost
> seems silly.
>

The use case is this:

def foo(it):
for x in it:
print(x)

def main():
it = iter([1, 2, 3])
next(it)
foo(it)

Since "for x in it" calls iter(it), if the argument is an iterator that
doesn't define __iter__, it would fail. But this is all about convention --
we want to make it convenient to do this kind of thing, so all standard
iterators define __iter__ as well as __next__.


> What worries me most about changing the current "requirement" is that it
> may create either confusion or backward compatibility issues for
> `collections.abc.Iterator` (which is a subtype of `Iterable`, and thus
> requires `__iter__`).
>

If you explicitly inherit from Iterator, you inherit a default
implementation of __iter__ (that returns self, of course). If you merely
register, it's up to you to comply. And sometimes people register things
that don't follow the letter of the protocol, just to get things going.
(This is common for complex protocols like Mapping, where some function you
have no control over insists on a Mapping but only calls one or two common
methods.

Duck typing is alive and kicking!

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

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


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

2021-09-14 Thread Brandt Bucher
Guido van Rossum wrote:
> On Tue, Sep 14, 2021 at 3:49 PM Brandt Bucher [email protected]
> wrote:
> > I think it's also worth noting that a missing "`__iter__` that returns
> > self" is trivial to recover from... just use a new reference to the
> > iterator instead. The overhead of a method call for this convention almost
> > seems silly.
> The use case is this:

Yeah, I understand that. But what I'm hinting that is that the `GET_ITER` 
opcode and `iter` builtin *could* gracefully handle this situation when called 
on something that doesn't define `__iter__` but does define `__next__`. 
Pseudocode:

def iter(o):
if hasattr(o, "__iter__"):
return o.__iter__()
elif hasattr(o, "__next__"):
# Oh well, o.__iter__() would have just returned o anyways...
return o
raise TypeError

This would be implemented at the lowest possible level, in `PyObject_GetIter`.

> > What worries me most about changing the current "requirement" is that it
> > may create either confusion or backward compatibility issues for
> > `collections.abc.Iterator` (which is a subtype of `Iterable`, and thus
> > requires `__iter__`).
> If you explicitly inherit from Iterator, you inherit a default
> implementation of __iter__ (that returns self, of course). If you merely
> register, it's up to you to comply. And sometimes people register things
> that don't follow the letter of the protocol, just to get things going.
> (This is common for complex protocols like Mapping, where some function you
> have no control over insists on a Mapping but only calls one or two common
> methods.

Yeah, I was thinking about cases like `isinstance(o, Iterator)`, where `o` 
defines `__iter__` but not `__next__`. Even though this code might start 
returning the "right" answer, it's still a backward-compatibility break. Not 
sure what the true severity would be, though...
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/SDZDMAF4MJDZHKIIWO2UUNRG6ZV2EU55/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Guido van Rossum
On Tue, Sep 14, 2021 at 4:33 PM Brandt Bucher 
wrote:

> Guido van Rossum wrote:
> > On Tue, Sep 14, 2021 at 3:49 PM Brandt Bucher [email protected]
> > wrote:
> > > I think it's also worth noting that a missing "`__iter__` that returns
> > > self" is trivial to recover from... just use a new reference to the
> > > iterator instead. The overhead of a method call for this convention
> almost
> > > seems silly.
> > The use case is this:
>
> Yeah, I understand that. But what I'm hinting that is that the `GET_ITER`
> opcode and `iter` builtin *could* gracefully handle this situation when
> called on something that doesn't define `__iter__` but does define
> `__next__`. Pseudocode:
>
> def iter(o):
> if hasattr(o, "__iter__"):
> return o.__iter__()
> elif hasattr(o, "__next__"):
> # Oh well, o.__iter__() would have just returned o anyways...
> return o
> raise TypeError
>
> This would be implemented at the lowest possible level, in
> `PyObject_GetIter`.
>

That seems like violating the Zen: "Errors should never pass silently." It
would certainly have a ripple effect, since everyone who currently defines
a __iter__ (in C or Python) that returns self would want to remove it, and
documentation would need to be updated everywhere. I don't see this issue
as important enough to do that. There are also probably multiple things
that emulate iter() that would have to be updated to match, if builtin
iter() starts changing its behavior.

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


> > > What worries me most about changing the current "requirement" is that
> it
> > > may create either confusion or backward compatibility issues for
> > > `collections.abc.Iterator` (which is a subtype of `Iterable`, and thus
> > > requires `__iter__`).
> > If you explicitly inherit from Iterator, you inherit a default
> > implementation of __iter__ (that returns self, of course). If you merely
> > register, it's up to you to comply. And sometimes people register things
> > that don't follow the letter of the protocol, just to get things going.
> > (This is common for complex protocols like Mapping, where some function
> you
> > have no control over insists on a Mapping but only calls one or two
> common
> > methods.
>
> Yeah, I was thinking about cases like `isinstance(o, Iterator)`, where `o`
> defines `__iter__` but not `__next__`.


(Did you mean the other way around? __iter__ without next is an Iterable
but not an Iterator. And isinstance() returns the right answer for this.)


> Even though this code might start returning the "right" answer, it's still
> a backward-compatibility break. Not sure what the true severity would be,
> though...
>

The ABC Iterator does not define the concept Iterator though. And static
type checking is not meant to exactly follow all the rules of the language
anyway -- there are many approximations being made by static type checkers.

Regarding the meaning of "requires", not all requirements are checked at
runtime either.

But I expect we won't be able to make everyone happy here.

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

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


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

2021-09-14 Thread Brandt Bucher
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).

Good point. I'm probably approaching this from the wrong angle (by trying to 
"fix" the language, rather than the docs).
___
Python-Dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/ZUESGSZ2BIBZZI42ZUMCQVWUX3STIO6V/
Code of Conduct: http://python.org/psf/codeofconduct/


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

2021-09-14 Thread Steven D'Aprano
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

Part of the problem is that there are two kinds of thing that we call 
"iterator":

1. Objects that we implicitly or explicitly pass to `iter()` in order to 
return an interator object; they only need to define an `__iter__` 
method that returns the actual iterator object itself.

(That's a slight simplification, because iter() will fall back on the 
Sequence Protocol if `__iter__` isn't defined. But to my mind, that 
makes Sequence Protocol objects *iterables* not iterators.)


2. Iterator objects themselves, which are defined by a protocol, not a 
type. The iterator object MUST define both `__iter__` and `__next__`, 
and the `__iter__` method MUST return self.


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


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

2021-09-14 Thread Steven D'Aprano
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/

We have objects such that:

iter(obj)

returns an iterator, but aren't themselves iterators. 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" :-(


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


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

2021-09-14 Thread Guido van Rossum
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
>

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"). But since this is a longstanding convention and matches
collections.abc.Iterator (and typing.Iterator) we might as well *document*
it to be the case.


> Part of the problem is that there are two kinds of thing that we call
> "iterator":
>
> 1. Objects that we implicitly or explicitly pass to `iter()` in order to
> return an interator object; they only need to define an `__iter__`
> method that returns the actual iterator object itself.
>

No, we don't call that an iterator. That's an *Iterable*. In this the docs
you point to are actually weak:

- It doesn't use the term Iterable at all but describe it as "container
objects" or "containers".

- It says " Sequences, described below in more detail, always support the
iteration methods." That's wrong, or at the very least misleading, since a
sequence itself *only* supports __iter__ -- it's the Iterator returned by
s.__iter__() that supports __next__.


> (That's a slight simplification, because iter() will fall back on the
> Sequence Protocol if `__iter__` isn't defined. But to my mind, that
> makes Sequence Protocol objects *iterables* not iterators.)
>

Right, it's wrong.


> 2. Iterator objects themselves, which are defined by a protocol, not a
> type. The iterator object MUST define both `__iter__` and `__next__`,
> and the `__iter__` method MUST return self.
>

So you say. I will compromise and agree that Iterators MUST have __next__
and SHOULD have __iter__ returning self. The distinction is that without
__next__ it's not an Iterator. But without __iter__ it's merely a broken
Iterator (that nevertheless works in most situations).

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

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


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

2021-09-14 Thread Guido van Rossum
On Tue, Sep 14, 2021 at 9:31 PM Steven D'Aprano  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)
*Pronouns: he/him **(why is my pronoun here?)*

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


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

2021-09-14 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 -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/54WUEDKDIT7FXH3JHL34VZDJCFV5Q3FH/
Code of Conduct: http://python.org/psf/codeofconduct/