【问题标题】:Does Python automatically optimize/cache function calls?Python 会自动优化/缓存函数调用吗?
【发布时间】:2018-08-11 19:28:56
【问题描述】:

我对 Python 比较陌生,经常看到类似的例子:

def max_wordnum(texts):
    count = 0
    for text in texts:
        if len(text.split()) > count:
            count = len(text.split())
    return count

重复的len(text.split()) 是否被Python 中的解释器/编译器以某种方式优化掉了,还是只需要将len(text.split()) 存储在变量中的CPU 周期的两倍?

【问题讨论】:

  • 不,不是。通话将进行两次。所以,还有优化代码的空间。
  • 很好的例子是这样写函数:max(len(text.split()) for text in texts)

标签: python


【解决方案1】:

重复的表达式不是“以某种方式优化掉”。使用局部变量来捕获和重用“已知不会改变”和“需要一些不重要的时间”来创建的结果;或者使用变量可以提高清晰度。

在这种情况下,Python 不可能知道 'text.split()' 是纯的 - pure function is one with no side-effects and always returns the same value for the given input

简单地说:Python 作为dynamically-typed language,在实际获取值之前甚至不知道“文本”的类型,因此不可能进行这种广义的优化。 (有些类可能会提供自己的内部“缓存优化”,但离题了..)

因为:即使是像 C# 这样具有静态类型的语言,也不会/不能优化一般的方法调用 - 同样,C# 中没有基本的可强制执行的纯度保证。 (即,如果该方法在第二次调用时返回不同的值或写入控制台怎么办?)

但是:Haskell, a Purely Functional language, 可以选择不“评估”两次调用,因为它是具有不同规则的不同语言...

【讨论】:

    【解决方案2】:

    即使python 做了优化了这个(事实并非如此),代码是复制/粘贴的,更难维护,所以创建一个变量来保存复杂的结果计算总是一个好主意。

    在这种情况下,一个更好的主意是使用 max 和一个键功能:

    return max(len(text.split()) for text in texts)
    

    这也更快。

    另请注意,len(text.split()) 创建了一个列表,您只需对项目进行计数。更好的方法是计算空格(如果单词仅由一个空格分隔)

    return max(text.count(" ") for text in texts) + 1
    

    如果可以有超过 1 个空格,请使用正则表达式和 finditer 以避免创建列表:

    return max(sum(1 for _ in re.finditer("\s+",text)) for text in texts) + 1
    

    注意最后加的1值修正值(分隔符的个数比字数少一)

    顺便说一句,即使值没有被缓存,你仍然可以在循环中使用复杂的表达式range

    for i in range(len(text.split())):
    

    range 对象是在开始时创建的,并且表达式只计算一次(例如与 C 循环相反)

    【讨论】:

      猜你喜欢
      • 2013-01-08
      • 2020-11-25
      • 2010-12-17
      • 1970-01-01
      • 2015-08-17
      • 2018-10-22
      • 2011-08-31
      • 2012-10-21
      • 2019-04-15
      相关资源
      最近更新 更多