在我看来,使用return变量而不是使用return语句意味着你应该跳过列表的副本。它不具有可读性,但我认为它会更快。
所以我测试了它:
import timeit
TEST_DATA = 10000000
ITERATIONS = 1000
time_taken = timeit.timeit(
"""
def get_big_list(test_data):
return [random.random() for _ in range(100000)]
return_list = get_big_list(test_data)
""",
setup='import random; test_data ={0}'.format(TEST_DATA), number=ITERATIONS)
print("return_list", time_taken / ITERATIONS)
# ----------------------------- SECOND TEST -----------------------------------
time_taken = timeit.timeit(
"""
def get_big_list(test_data, return_list):
[return_list.append(random.random()) for _ in range(100000)]
return_list = []
get_big_list(test_data, return_list)
""",
setup='import random; test_data ={0}'.format(TEST_DATA), number=ITERATIONS)
print("return_list", time_taken / ITERATIONS)
我对收到的数字感到非常惊讶,我不明白为什么返回语句更快。
$ python large_list_return.py
('return_list', 0.013130356788635254)
('return_list', 0.022573610067367553)
$ python3 large_list_return.py
return_list 0.016797171516984236
return_list 0.02749005461903289
我发现另一个有趣的事情是使用for循环来加入比使用列表理解更快。
time_taken = timeit.timeit(
"""
def get_big_list(test_data, return_list):
for index in range(100000):
return_list.append(random.random())
return_list = []
get_big_list(test_data, return_list)
""",
setup='import random; test_data ={0}'.format(TEST_DATA), number=ITERATIONS)
返回这些数字
python large_list_return.py
('return_list', 0.0133241708278656)
('return_list', 0.019642770051956176)
python3 large_list_return.py
return_list 0.017075919962022453
return_list 0.024502045304980128
答案 0 :(得分:3)
除非您明确要求副本(例如,通过获取列表的切片),否则Python不会制作副本 - 您只需获得对已创建的列表的另一个引用。
另一方面, append
可能需要获得更多内存并复制以前的内容 - 它是分摊的O(1),但它仍然需要做更多的工作。
此外,因为你使用列表推导来应该是一个循环:
[return_list.append(random.random()) for _ in range(100000)]
在你的第二个实现中,你也创建另一个列表(然后你就扔掉了),一个组成了十万个None
(返回值来自append
。这就是for
更快的原因 - 它避免无用地创建冗余列表。
如果您正在寻找优化,请考虑提升命名空间查找,正如我在评论中提到的那样。具体来说,使用:
def get_big_list(test_data):
r = random.random
return [r() for _ in range(100000)]
在我过时的笔记本电脑上,这比你的第一个版本的17(这告诉我们每个random.random
查找大约需要50纳秒)需要12毫秒。