有人可以向我解释一下这两种创建列表方式之间的区别吗?它们是一样的吗 ?如果不是,我应该使用哪一个?
squares1 = [x**2 for x in range(1, 11)]
squares2 = list(x**2 for x in range(1, 11))
答案 0 :(得分:3)
从以下方面可以看出它们的性能略有不同:
squares1 = [x**2 for x in range(1, 11)]
每个循环3.07 µs±70 ns(平均±标准偏差,共运行7次,每个循环100000次)
squares2 = list(x**2 for x in range(1, 11))
每个循环3.65 µs±35.6 ns(平均±标准偏差,共运行7次,每个循环100000次)
这可能主要是因为在情况1中,您正在同时迭代并生成列表的值。
在情况2中,您在迭代时生成值,然后在其结束时将其转换为列表,然后将其存储为给定变量。
答案 1 :(得分:2)
我认为,第一个程序通过列表理解直接将squares1初始化为列表。
另一个首先创建一个生成器类对象,然后将其转换为列表。我认为第一种方法更有效。
列表和生成器之间几乎没有什么区别,但是根据我的知识和经验,列表可以更快地完成工作,而生成器则懒惰地为每次迭代生成单个结果。对于您的大多数任务,建议您选择列表。
答案 2 :(得分:1)
第一种方法更快。这是因为当它们被编译成字节码时,第一个变成了
0 LOAD_CONST 0 (<code object <listcomp> at 0x7fc95aea9ed0, file "<dis>", line 1>)
2 LOAD_CONST 1 ('<listcomp>')
4 MAKE_FUNCTION 0
6 LOAD_NAME 0 (range)
8 LOAD_CONST 2 (1)
10 LOAD_CONST 3 (11)
12 CALL_FUNCTION 2
14 GET_ITER
16 CALL_FUNCTION 1
18 RETURN_VALUE
第二个变成
0 LOAD_NAME 0 (list)
2 LOAD_CONST 0 (<code object <genexpr> at 0x7fc95aea9ed0, file "<dis>", line 1>)
4 LOAD_CONST 1 ('<genexpr>')
6 MAKE_FUNCTION 0
8 LOAD_NAME 1 (range)
10 LOAD_CONST 2 (1)
12 LOAD_CONST 3 (11)
14 CALL_FUNCTION 2
16 GET_ITER
18 CALL_FUNCTION 1
20 CALL_FUNCTION 1
22 RETURN_VALUE
这意味着第二种方法需要再执行两条指令,即使只是很小的一点,速度也会变慢。
在我的笔记本电脑上,第一个方法的一百万次迭代花费4.651s,第二个方法的一百万次迭代花费5.483s。
答案 3 :(得分:0)
在第一种情况下,您使用列表理解语法。这是在python列表中映射某些功能的最快方法。
在第二种情况下,您创建一个generator
(x**2 for x in range(1000))
并将其立即发送到list()函数。您的情况几乎没有区别,因为您获得相同的列表和几乎相同的执行时间:
%%timeit
[i**2 for i in range(1000)]
Out:
170 µs ± 774 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
list(i**2 for i in range(1000))
Out:
187 µs ± 2.45 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
但是我不确定这两种情况下的内存使用情况-看起来它们是相同的。