3 回答
TA贡献1911条经验 获得超7个赞
更多代码行是否意味着性能降低的问题是有缺陷的,因为两者都不是less lines ≠ performance ≠ more lines
。性能取决于 Python 代码如何解析为执行它的底层 C 函数调用,这主要是解析器/解释器的实现细节,与行数没有一一对应。
也就是说,在选择循环、列表理解和映射时需要考虑以下几点。
当代码的目的是创建某个内容的列表时,列表推导式通常比循环更快。据我所知,这与第二次调用追加方法有关,而且因为增量列表构造可能会导致列表大小调整,从而导致一些内存重新分配开销。
无论在哪里调用,调用 python 函数都是一个缓慢的操作。引用这个伟大的答案:
A function call needs to manipulate the stack, pushing the local frame onto it, creating a new frame, then clear it all up again when the function returns.
一个例外是用 C 编写的函数,例如来自操作员模块的函数,它们比本地 Python 对应项稍快。
也就是说,我已经使用与此类似的代码进行了一些分析,并且我的测试表明循环是最慢的选项。有趣的是,测试还表明地图比列表理解稍快(与链接的答案相反)。代码及结果如下:
ls = list(range(1000000))
def f(x):
return x+1
def list_comprehension(ls):
return [f(x) for x in ls]
def for_loop(ls):
arr = []
for x in ls:
arr.append(f(x))
return arr
def map_(ls):
return list(map(f, ls))
if __name__ == "__main__":
import cProfile
for fn in [list_comprehension, for_loop, map_]:
print('=' * 25)
print("Profiling:", fn.__name__)
print('=' * 25)
pr = cProfile.Profile()
for i in range(1000):
pr.runcall(fn, ls)
pr.create_stats()
pr.print_stats()
# Output
=========================
Profiling: list_comprehension
=========================
1000003000 function calls in 235.641 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000000000 104.000 0.000 104.000 0.000 aa.py:5(f)
1000 0.008 0.000 235.640 0.236 aa.py:8(list_comprehension)
1000 131.632 0.132 235.632 0.236 aa.py:9(<listcomp>)
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
=========================
Profiling: for_loop
=========================
2000002000 function calls in 410.884 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000 242.083 0.242 410.883 0.411 aa.py:11(for_loop)
1000000000 107.727 0.000 107.727 0.000 aa.py:5(f)
1000000000 61.073 0.000 61.073 0.000 {method 'append' of 'list' objects}
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
=========================
Profiling: map_
=========================
1000002000 function calls in 205.035 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1000 102.451 0.102 205.034 0.205 aa.py:17(map_)
1000000000 102.583 0.000 102.583 0.000 aa.py:5(f)
1000 0.001 0.000 0.001 0.000 {method 'disable' of '_lsprof.Profiler' objects}
无论如何,在这种情况下最好的办法是写下所有不同的版本并自己进行分析,而不是依赖一般假设。
TA贡献1993条经验 获得超5个赞
单行代码可能比较长的代码更快,但这不是一般规则。一些允许非常紧凑的代码的 python 函数(如 any()、all() 等)经过优化,可以非常快速地执行,并且可能比 (例如)几个执行相同工作的嵌套循环。编译器/解释器并不真正关心它必须处理多少文本(除非您的代码由数千行代码组成)。单行是首选,因为它节省了空间并使代码更具可读性。
TA贡献1893条经验 获得超10个赞
行数与代码的执行完全无关。py 文件将被读取一次、解析和编译。随后,将执行编译后的代码。
换句话说,如果您创建一个包含 10 GB 空白的文件,是的,这会影响解析时间,但即使如此,执行也不会受到影响。
两种变体之间的区别在于,一种使用列表理解来创建列表,而另一种则创建一个空列表,然后填充它。我的直觉是,列表理解理论上更容易优化,但如果你真的关心微小的差异,你应该分析它。
另一方面,执行时间的微小差异很少会导致代码看起来更糟糕,因此默认情况下您应该始终选择更优雅的解决方案。
添加回答
举报