Python keeps surprising me
So one of the things that’s always bugged me about Python and other languages with ‘foreach’ sorts of iteration are those times when you iterate over a list and need to do something that requires an index, or that requires you to iterate it back-to-front, or that requires you to iterate multiple lists simultaneously.I used to write such loops like this:
for n in range(len(mylist)):
print n, mylist[i]
The disadvantage of that is that you have to take the length of the list, and generate a range object, etc. It’s wasteful.
But today I was reading PEP 322 about the reversed() function, and I came across this sentence:
“Like its cousins, zip() and enumerate(), [reversed()] needs to be directly accessible in daily programming. Each solves a basic looping problem: lock-step iteration, loop counting, and reverse iteration.”
And I suddenly went “DOH!”
I’ve used zip() before, and reversed(), but I didn’t even know about enumerate(). Upon reading that sentence, a couple of annoying idiosyncrasies I thought Python had vanished into thin air.
So that code I wrote before should properly be written as:
for n, item in enumerate(mylist):
print n, item
That’s the magic of python’s generators. I presume that enumerate is written as a generator, almost as simply as this:
def enumerate(iterable):
i = 0
for item in iterable:
yield i, item
i += 1
The result is that it’s compact, obvious in its usage, and it doesn’t use items from a generator until it needs one. It can even cope with infinite generators (generators that never stop and don’t have a “length”).
The more I use this language (and it’s been 5 years now), the more I like it.