【问题标题】:Python quick question about comprehensions vs list comprehensions关于推导式与列表推导式的 Python 快速问题
【发布时间】:2020-02-14 10:35:25
【问题描述】:

只是想问一下这是为什么(如果我没记错的话,请列出理解):

def s(number):
    return sum([n for n in range(number) if n%3==0 or n%5==0])
s(100)

速度是这个(202 步)的两倍(可视化 python 108 步):

def s(number):
    return sum(n for n in range(number) if n%3==0 or n%5==0)
s(100)

?

而且,虽然第一个代码更快,但第二个代码在任何情况下都有什么优势吗?也许,使用更少的内存?只是吐口水,真的不知道我在说什么。任何澄清将不胜感激。

【问题讨论】:

  • 第一个是在内存中创建一个完整的列表,然后再次遍历该列表到sum它。第二个sums 项目直接由生成器表达式生成。第一个效率较低,但由于执行的可视化方式,第二个可能被可视化为采取更多步骤……顺便说一句,请链接到该可视化器……
  • @John Doe 您是否对这两个功能进行了基准测试?当我timeit 时,我没有看到太大的不同。可能是可视化器中显示的步骤完全取决于代码的可视化方式?(即,不是性能)
  • "列表理解更快,因为它针对 Python 解释器进行了优化,可以在循环期间发现可预测的模式。"见这篇文章:click here
  • @abdulNiyasPM 我实际上并没有“计时”,只是在上面提供的链接上将其可视化。看来我应该有。那么这两种方法在性能/内存使用方面完全相同吗?

标签: python list list-comprehension


【解决方案1】:

你的两个 sn-ps 的性能非常相似,显然不是每一步都是平等的。对于较小的 number 值,第一个代码(列表)稍快,但对于较大的 number,第二个代码(生成器)胜出。

另一件事是内存使用 - 创建列表需要与其大小成正比的内存量,因此较大的number 会消耗更多的 RAM。此外,随着列表的增长,它需要重新分配内存,这最终会触发垃圾收集器(timeit() 默认情况下禁用gc,导致结果混乱)。 另一方面,生成器版本对任何number 使用相同(最少)的内存量。

结论是您应该尽可能使用生成器表达式。当您关心内存占用和/或对大量数据进行操作时,这一点尤其重要。此外,这样您的代码会更短更简洁(有争议)。

PEP 289 中解释了这个主题,介绍了生成器表达式。

【讨论】:

  • 感谢您提供如此全面的回答!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-13
  • 2018-10-30
  • 2012-05-04
  • 1970-01-01
相关资源
最近更新 更多