我对 Python 还比较陌生,我正在尝试优化一些 HackerRank 问题的代码。我发现使用range(即生成列表?)比仅使用while带有单个变量的循环进行迭代更快,这很奇怪。
range
while
我想知道,如果我稍后在代码中迭代相同的序列,缓存函数的结果是否会更快range。例如:
这更快吗:
ten = 10 zeroToTen = range(ten) sum = 0 for x in zeroToTen: sum += x product = 1 for y in zeroToTen: product *= y
或者我应该range每次都回忆一下:
ten = 10 sum = 0 for x in range(10): sum += x product = 1 for y in range(10): product *= y
这是一个有趣的 Python 性能问题,特别是当你试图在竞赛编程或优化脚本中寻找最佳实践时!我们来分析这两种方法的性能和适用场景。
range(n) 在内存上非常高效,不会存储整个序列。
range(n)
缓存 range:
当你将 range 赋值给变量(如 zeroToTen),它不会重新生成。变量仅是对 range 对象的引用,后续循环会复用这个对象。
zeroToTen
重新调用 range:
range(10)
让我们对两种情况进行简单的性能测试,使用 Python 的 timeit 模块。
timeit
import timeit def cached_range(): ten = 10 zeroToTen = range(ten) sum_ = 0 for x in zeroToTen: sum_ += x product = 1 for y in zeroToTen: product *= y def uncached_range(): ten = 10 sum_ = 0 for x in range(ten): sum_ += x product = 1 for y in range(ten): product *= y print("Cached range:", timeit.timeit(cached_range, number=100000)) print("Uncached range:", timeit.timeit(uncached_range, number=100000))
重复迭代相同的序列: 如果你需要多次遍历相同的 range 对象,那么缓存是一个好习惯。例如: py r = range(1000) for i in r: pass for j in r: pass # 重用已经生成的 range 对象
py r = range(1000) for i in r: pass for j in r: pass # 重用已经生成的 range 对象
大范围的 range: 如果范围非常大(如 range(10**6)),缓存可以避免多次创建迭代器的开销。
range(10**6)
在性能敏感的代码中: 如果代码执行频率很高(如内层循环),缓存 range 可以略微减少开销。
单次使用: 如果只需要使用一次 range,直接调用即可,缓存不会带来任何实际性能提升。
Python 3 的优化: 在现代 Python(3.x)中,range 本质上是惰性生成的对象,性能非常高效,因此多次调用 range 的开销很小。
在你的例子中,差异会非常小,大多取决于场景。如果你的问题偏向性能敏感并多次使用 range,使用缓存版本会稍微快一些。但如果你只使用一次,不必缓存它。
对于 Pythonic 的写法和清晰性,建议如下: - 单次使用时直接调用 range: py for x in range(10): ... - 多次使用时缓存 range: py zero_to_ten = range(10) for x in zero_to_ten: ... for y in zero_to_ten: ...
py for x in range(10): ...
py zero_to_ten = range(10) for x in zero_to_ten: ... for y in zero_to_ten: ...