【发布时间】:2021-11-30 13:29:20
【问题描述】:
如果我一直在一个很长的列表上调用 len(),我是在浪费时间,还是在后台保留一个 int 计数?
【问题讨论】:
-
这总是困扰着我。特别是当我的分析器告诉我,我花了 2.2 秒的时间运行了一个运行一分钟的程序来调用这个函数。
标签: python
如果我一直在一个很长的列表上调用 len(),我是在浪费时间,还是在后台保留一个 int 计数?
【问题讨论】:
标签: python
别担心:它当然会节省计数,因此列表上的len() 是一个非常便宜的操作。顺便说一句,字符串、字典和集合也是如此!
【讨论】:
如果您不想自己下载源代码,另一种方法是 to look it up on Google Code Search look at the source on GitHub。
static Py_ssize_t list_length(PyListObject *a)
{
return a->ob_size;
}
【讨论】:
【讨论】:
编写您的程序,使其优化清晰且易于维护。致电len(foo),您的程序是否更清晰?然后这样做。
您是否担心花费的时间?使用timeit module in the standard library 来测量所花费的时间,并查看它在您的代码中是否重要。
与大多数人一样,您很可能会错误地猜测程序的哪些部分最慢。避免猜测的诱惑,而是通过测量来找出答案。
请记住,用 Donald Knuth 的话来说,过早的优化是万恶之源。只关注您测量速度的代码速度,以了解改变其工作方式所带来的好处是否值得付出代价。
【讨论】:
问题已得到解答(len 为 O(1)),但您可以通过以下方式自行检查:
$ python -m timeit -s "l = range(10)" "len(l)"
10000000 loops, best of 3: 0.119 usec per loop
$ python -m timeit -s "l = range(1000000)" "len(l)"
10000000 loops, best of 3: 0.131 usec per loop
是的,不是很慢。
【讨论】:
Python“列表”实际上是一个可调整大小的数组,而不是链表,因此它将大小存储在某个地方。
【讨论】:
我来晚了,但我刚刚做了一个测试,得到了一些有趣的结果:
import timeit, statistics
test_arr = list(range(1000000))
# Just call len() every time
def test1(arr):
for i in range(len(arr)):
j = arr[len(arr)-1]
# Store the result of len()
def test2(arr):
l = len(arr)
for i in range(len(arr)):
j = arr[l-1]
print("Running test 1...")
t1 = timeit.repeat(lambda: test1(test_arr), number=int(2e2), repeat=4)
print("Test 1 results:")
print(t1)
print("Running test 2...")
t2 = timeit.repeat(lambda: test2(test_arr), number=int(2e2), repeat=4)
print("Test 2 results:")
print(t2)
m1 = statistics.mean(t1)
m2 = statistics.mean(t2)
avg = round(100 * abs(m2-m1)/m1, 2)
sign = "quicker" if m1-m2 > 0 else "slower"
print(f"On average, test 2 was {avg} {sign} than test 1")
结果:
Running test 1...
Test 1 results:
[15.189714099979028, 15.160469999769703, 15.17295220005326, 15.072236399864778]
Running test 2...
Test 2 results:
[8.17264029989019, 8.191439799964428, 8.171442999970168, 8.208112000022084]
On average, test 2 was 45.96 quicker than test 1
这是一个非常粗略的测试,我相信有人可以改进它(或指出错误),但似乎只调用一次 len 并将其保存到变量中确实要快得多,而不是而不是反复调用它(我相信这是发帖人所要求的)。
【讨论】:
len()(或不调用它)之外没有其他实际工作。对于一个还可以做其他工作的函数,len() 的价格可能会消失......
len 别名为本地,即可将 test1 的时间缩短约 17%。全局/模块查找在 CPython 中也很昂贵。
它必须在某处存储长度,因此您不必每次都计算项目数。
【讨论】: