简体   繁体   中英

Only index needed: enumerate or (x)range?

If I want to use only the index within a loop, should I better use the range/xrange function in combination with len()

a = [1,2,3]
for i in xrange(len(a)):
    print i 

or enumerate ? Even if I won't use p at all?

for i,p in enumerate(a):
    print i    

我会使用enumerate因为它更通用 - 例如它将在迭代和序列上工作,并且仅仅返回对象的引用的开销并不是那么大 - 而xrange(len(something))虽然(对我而言)因为你的意图更容易阅读 - 将在不支持len对象上打破...

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.

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

xrange应该快一点,但枚举意味着当你意识到你需要p afterall时你不需要改变它

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.

Code:

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

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 = [0]
a = a * 1000000
time.perf_counter()

for i,j in enumerate(a):
    pass

print(time.perf_counter())

script for range

import time
a = [0]
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

Just use 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM