[Python-ideas] Consider making enumerate a sequence if its argument is a sequence
Steven D'Aprano
steve at pearwood.info
Thu Oct 1 17:10:28 CEST 2015
On Thu, Oct 01, 2015 at 08:15:25AM +0300, Akira Li wrote:
> True or false?: do all iterables return the same items twice?
> http://www.fallacyfiles.org/loadques.html
[Aside: I have no idea what point you are making with the above link.]
Of course they don't necessarily do so, but those that don't are not
necessarily well-behaved.
In the case of sequences and collections, the concept is that (absent
any explicit mutation operation), iterating over it twice *should* give
the same results, that is the normal expectation. But that isn't
enforced, we can write something that breaks that rule:
class WeirdIterable:
def __getitem__(self, i):
if random.random() > 0.9: raise IndexError
return random.choice(["fe", "fi", "fo", "fum"])
but most people would consider that to be a pathological case. Yes, you
can do it, and maybe you have a reason to do so, but you can't expect
other people's code to deal with it gracefully.
In the case of iterators, the answer is *certainly not*.
Iterators are designed for the express purpose of handling not just the
"lazy sequence" case where you choose to calculate results on demand as
an optimization, but the case where you *have no choice* because the
results are coming from some source which may change from run to run,
e.g. an external data source. An iterator *may* repeat if run twice, but
there is no expectation that it will do so. It's not just that the rule
about repeatability is not enforced, but that there is no such rule in
the first place.
(By the way, when I talk about running an iterator twice, I'm completely
aware that technically you cannot ever do so. What I mean is to iterate
over the object, then *recreate the object* in some sense, then iterate
over it again.)
> Specific application may use more specific requirements e.g.:
>
> list(iterable):
>
> - does it mean that all iterables must be finite?
> - do we need a special word to describe what list() accepts?
No, and no.
In principle, list() will quite happily create an infinite list for you,
if you have infinite memory :-) The fact that in practice lists are
probably limited to something of the order of 2**64 items or less is a
mere quality of implementation issue :-)
But to be more serious, no, in context we should understand that lists
have actual physical limits, and even finite iterables may not be
capable of being turned into lists:
def gen():
for i in range(10**10000):
yield i
Perfectly finite in size, but you cannot have a list that big. It's not
just *infinite iterables* which are prohibited, that's just a special
case of iterables that will provide more items than you have memory to
store. And that's not a fixed limit, it will differ from machine to
machine.
[...]
> You've got the idea: the word *iterable* may be used in the context when
> not all iterables are accepted.
Sure. But the distinction is that while there are a whole lot of
different iterables:
- iterables with a sufficiently small number of items
- iterables of hashable items
- iterables of (hashable key, item) pairs
- iterables of prime numbers less than one million
- iterables of strings containing exactly 1 vowel
etc they are special cases and don't need specialised names. But there
is a *general* distinction between two cases:
- iterables which are iterators
- iterables which are not iterators
We have a name for the first set: "iterators". But we don't have a name
for the second set. Andrew suggested "non-iterator iterables" is too
clumsy for general use, and suggests we need a better name. You
suggested "iterables", but that clearly cannot work, since iterators are
a kind of iterable.
--
Steve
More information about the Python-ideas
mailing list