如果我只想在循环中使用索引,我是否应该更好地使用range/xrange
函数与len()
结合使用?
a = [1,2,3]
for i in xrange(len(a)):
print i
使用 enumerate
还是 p
?即使我完全不会用到 p
?
for i,p in enumerate(a):
print i
我会使用 enumerate
,因为它更加通用——例如,它可以在可迭代对象和序列上正常工作,并且仅返回对对象的引用的开销并不是很大。而 xrange(len(something))
(对我来说)虽然更容易读懂你的意图,但在不支持 len
的对象上会出错...
len()
的例子?函数? - LarsVegasitertools.count(10)
是一个生成器。 - jamylakitertools.count(10)
是一个无限生成器,因此您也不想对其进行枚举。 - Sven Marnachitertools.islice(itertools.count(10, 2), 50, 100)
可能是一个更好的例子,尽管你也可以使用数学来创建一个从中得到xrange
。 - jamylakiter([])
更加简洁。 :) - Sven Marnach使用xrange和len结合的情况很常见,所以如果你只需要通过索引访问值,那么可以使用它。
但是,如果出于某些原因你更喜欢使用enumerate,你可以使用下划线(_),这只是一个经常看到的符号表示你不会以有意义的方式使用变量:
for i, _ in enumerate(a):
print i
使用下划线(_)时也可能会遇到一个陷阱。在i18n库和系统中,将“翻译”函数命名为_是常见的做法,因此请小心在使用gettext或其他类似库时使用它(感谢@lazyr)。
gettext
结合使用,因为它会将 _
变量用于其他用途,并且这种用法会遮蔽当前命名空间中的 gettext
_
。这可能会导致奇怪的错误。 - Lauritz V. Thaulowunused_xxx
或类似模式。 - Sven Marnach这是一个罕见的要求 - 容器中仅使用其长度信息!在这种情况下,我确实会明确这个事实并使用第一个版本。
p
时不需要更改。
我进行了时间测试,发现 range 比 enumerate 快约两倍。(在Python 3.6 Win32平台上)
在长度为1M的情况下,取三次最佳结果:
希望对你有所帮助。
顺带一提,我最初开展这项测试是为了比较 Python 和 VBA 的速度...结果发现 VBA 的速度实际上比 range 方法快7倍...难道这是我 Python 技能不精的原因吗?
毫无疑问,Python 肯定可以以某种方式做得比 VBA 更好。
enumerate 脚本如下:
import time
a = [0]
a = a * 1000000
time.perf_counter()
for i,j in enumerate(a):
pass
print(time.perf_counter())
import time
a = [0]
a = a * 1000000
time.perf_counter()
for i in range(len(a)):
pass
print(time.perf_counter())
VBA脚本(0.008秒)
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
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))
a = testlist[i] + 1
和 b = x + 1
这两行时,你会发现 range(len()) 更快。range(len()):
18.766527627612255
enum():
15.353173553868345
range(len()):
8.231641875551514
enum():
9.974262515773656
根据您的示例代码,
res = [[profiel.attr[i].x for i,p in enumerate(profiel.attr)] for profiel in prof_obj]
我会用另一个替换它
res = [[p.x for p in profiel.attr] for profiel in prof_obj]
只需使用range()
。如果你要使用所有的索引,xrange()
没有任何实际的好处(除非len(a)
非常大)。而enumerate()
创建了一个更丰富的数据结构,但你会立即将其丢弃。
xrange
不是生成器。它是一个序列对象,可以进行惰性求值。 - jamylakrangeiterator
,它遍历xrange
序列。例如,当您编写for i in xrange(3)
时,它会调用iter(xrange(3))
以获取rangeiterator
。 - jamylak
enumerate
[[profiel.attr[i].x for i,p in enumerate(profiel.attr)] for profiel in prof_obj]
。p
是不需要的,或者应该是[[p.attr.x for p in profiel.attr] for profiel in prof_obj]
。所以我问自己是否应该重写代码的某个地方... - LarsVegassum_dist = [[sum(afst[:i]) for i,_ in enumerate(afst,start=1)] for afst in dist_betw]
。(尽管我知道这个结构并不是必须的,因为我也可以使用itertools.accumulate()
) - LarsVegasitertools.accumulate()
是显而易见的选择。如果可以使用NumPy,则还可以使用numpy.cumsum()
。在所有其他情况下,只需编写自己的O(n)cumsum()
函数即可。 - Sven Marnachcumsum
函数,但后来有了这个想法。当然,你说的二次复杂度是正确的,但由于我处理的数据集非常小,所以这并没有让我感到可能会出问题。不过,还是谢谢你指出来给我。 - LarsVegas