On 30.09.2015 21:19, Andrew Barnert wrote:
On Sep 30, 2015, at 11:43, M.-A. Lemburg email@example.com wrote:
On 30.09.2015 20:26, Andrew Barnert via Python-ideas wrote:
On Sep 30, 2015, at 11:11, M.-A. Lemburg firstname.lastname@example.org wrote:
On 30.09.2015 19:19, Neil Girdhar wrote: I guess, I'm just asking for enumerate to go through the same change that range went through. Why wasn't it a problem for range?
range() returns a list in Python 2 and a generator in Python 3.
No it doesn't. It returns a (lazy) sequence. Not a generator, or any other kind of iterator.
You are right that it's not of a generator type and more like a lazy sequence. To be exact, it returns a range object and does implement the iter protocol via a range_iterator object.
To be exact, it returns an object which returns True for isinstance(r, Sequence), which offers correct implementations of the entire sequence protocol. In other words, it's not "more like a lazy sequence", it's _exactly_ a lazy sequence.
In 2.3-2.5, xrange was a lazy "sequence-like object", and the docs explained how it didn't have all the methods of a sequence but otherwise was like one. When the collections ABCs were added, xrange (2.x)/range (3.x) started claiming to be a sequence, but the implementation was incomplete, so it was defective. This was fixed in 3.2 (which also made all of the sequence methods efficient—e.g., a range that fits into C longs can test an int for __contains__ in constant time).
I don't know why so many people seem to believe it returns a generator. (And, when you point out what it returns, most of them say, "Why was that changed from 2.x xrange, which returned a generator?" but xrange never returned a generator either--it returned a lazy almost-a-sequence from the start.)
Perhaps because it behaves like one ? :-)
Unlike an iterator, it doesn't iterate over a sequence, but instead generates the values on the fly.
You're confusing things even worse here.
I guess I used the wrong level of detail. I was trying explain things in terms of concepts, not object types, isinstance() and ABCs.
The reason was that the subject line makes a suggestion which simply doesn't fit the main concept behind enumerate: that of generating values on the fly instead of allocating them as sequence.
We just got side tracked with range(), since Neil brought this up as example of why changing enumerate() should be possible.
Back on the topic:
arg = range(10) e = enumerate(arg) e
<enumerate object at 0x7fcbbc57bd80>
import collections isinstance(e, collections.Sequence)
The way I understand the proposal is that Neil wants the above to return:
iff isinstance(arg, collections.Sequence)
and because this only makes sense iff e doesn't actually create a list, enumerate(arg) would have to return a lazy/virtual/whatever-term-you-use-for-generated-on-the-fly sequence :-)
Regardless of this breaking backwards compatibility, what's the benefit of such a change ?
Just like range(), enumerate() is most commonly used in for-loops, so the added sequence-ishness doesn't buy you anything much (except the need for more words in the glossary :-)).