Each Answer to this Q is separated by one/two green lines.
If I want to use only the index within a loop, should I better use the
range/xrange function in combination with
a = [1,2,3] for i in xrange(len(a)): print i
enumerate? Even if I won’t use
p at all?
for i,p in enumerate(a): print i
I would use
enumerate as it’s more generic – eg it will work on iterables and sequences, and the overhead for just returning a reference to an object isn’t that big a deal – while
xrange(len(something)) although (to me) more easily readable as your intent – will break on objects with no support for
Using xrange with len is quite a common use case, so yes, you can use it if you only need to access values by index.
But if you prefer to use enumerate for some reason, you can use underscore (_), it’s just a frequently seen notation that show you won’t use the variable in some meaningful way:
for i, _ in enumerate(a): print i
There’s also a pitfall that may happen using underscore (_). It’s also common to name ‘translating’ functions as _ in i18n libraries and systems, so beware to use it with gettext or some other library of such kind (thnks to @lazyr).
That’s a rare requirement – the only information used from the container is its length! In this case, I’d indeed make this fact explicit and use the first version.
xrange should be a little faster, but enumerate will mean you don’t need to change it when you realise that you need
I ran a time test and found out range is about 2x faster than enumerate. (on python 3.6 for Win32)
best of 3, for len(a) = 1M
- enumerate(a): 0.125s
- range(len(a)): 0.058s
Hope it helps.
FYI: I initialy started this test to compare python vs vba’s speed…and found out vba is actually 7x faster than range method…is it because of my poor python skills?
surely python can do better than vba somehow
script for enumerate
import time a =  a = a * 1000000 time.perf_counter() for i,j in enumerate(a): pass print(time.perf_counter())
script for range
import time a =  a = a * 1000000 time.perf_counter() for i in range(len(a)): pass print(time.perf_counter())
script for vba (0.008s)
Sub timetest_for() Dim a(1000000) As Byte Dim i As Long tproc = Timer For i = 1 To UBound(a) Next i Debug.Print Timer - tproc End Sub
Based on your sample code,
res = [[profiel.attr[i].x for i,p in enumerate(profiel.attr)] for profiel in prof_obj]
I would replace it with
res = [[p.x for p in profiel.attr] for profiel in prof_obj]
I wrote this because I wanted to test it.
So it depends if you need the values to work with.
testlist =  for i in range(10000): testlist.append(i) def rangelist(): a = 0 for i in range(len(testlist)): a += i a = testlist[i] + 1 # Comment this line for example for testing def enumlist(): b = 0 for i, x in enumerate(testlist): b += i b = x + 1 # Comment this line for example for testing import timeit t = timeit.Timer(lambda: rangelist()) print("range(len()):") print(t.timeit(number=10000)) t = timeit.Timer(lambda: enumlist()) print("enum():") print(t.timeit(number=10000))
Now you can run it and will get most likely the result, that enum() is faster.
When you comment the source at
a = testlist[i] + 1 and
b = x + 1 you will see range(len()) is faster.
For the code above I get:
range(len()): 18.766527627612255 enum(): 15.353173553868345
Now when commenting as stated above I get:
range(len()): 8.231641875551514 enum(): 9.974262515773656
range(). If you’re going to use all the indexes anyway,
xrange() provides no real benefit (unless
len(a) is really large). And
enumerate() creates a richer datastructure that you’re going to throw away immediately.