功能关闭性能

max*_*max 8 python performance implementation closures python-3.x

当我替换这段代码时,我认为我提高了性能:

def f(a, b):
  return math.sqrt(a) * b
result = []
a = 100
for b in range(1000000):
  result.append(f(a, b))
Run Code Online (Sandbox Code Playgroud)

有:

def g(a):
  def f(b):
    return math.sqrt(a) * b
  return f
result = []
a = 100
func = g(a)
for b in range(1000000):
  result.append(func(b))
Run Code Online (Sandbox Code Playgroud)

我假设自从a在执行闭包时修复,解释器将预先计算所涉及的所有内容,a因此math.sqrt(a)将重复一次而不是1000000次.

根据实施情况,我的理解总是正确的,或总是不正确,或正确/不正确?

我注意到代码对象func是在运行时之前构建的(至少在CPython中),并且是不可变的.然后代码对象似乎使用全局环境来实现闭包.这似乎表明我希望的优化不会发生.

Nik*_* B. 13

我假设因为在执行闭包时a是固定的,解释器会预先计算涉及a的所有内容,因此math.sqrt(a)将重复一次而不是1000000次.

这个假设是错误的,我不知道它来自哪里.闭包只捕获变量绑定,在你的情况下它捕获值的值a,但这并不意味着还有更多的魔法:math.sqrt(a)每次f调用时表达式仍会被评估.

毕竟,它拥有所有的时间,因为解释器不知道被计算sqrt为"纯"(返回值仅取决于参数和执行没有副作用).像你期望的那样优化在函数式语言中是实用的(引用透明性和静态类型在这里有很多帮助),但在Python中很难实现,这是一种命令式和动态类型的语言.

也就是说,如果要预先计算其值math.sqrt(a),则需要明确地执行此操作:

def g(a):
  s = math.sqrt(a)
  def f(b):
    return s * b
  return f
Run Code Online (Sandbox Code Playgroud)

或使用lambda:

def g(a): 
  s = math.sqrt(a)
  return lambda b: s * b
Run Code Online (Sandbox Code Playgroud)

现在g真的返回一个带有1个参数的函数,你必须只用一个参数调用结果.

  • 如果不运行Python程序,你无法告诉它.你能做的最好的事情就是猜测.想象一下设置`math.sqrt = lambda*args:input("Anything goes")`***会对函数做什么. (2认同)