了解 Python 闭包

Posted

技术标签:

【中文标题】了解 Python 闭包【英文标题】:Understanding Python Closures 【发布时间】:2015-07-29 15:55:30 【问题描述】:

我一直认为 Python 2.7 的函数是指定义它们的作用域。考虑以下代码。为什么第二个输出不是“calculating: sin”

有什么方法可以修改代码以使其按预期工作?

import math

mymath = dict()

for fun in ["sin", "cos"]:
    def _impl(val):
        print "calculating: %s" % fun
        return getattr(math, fun)(val)
    mymath[fun] = _impl

# calculating: cos
print mymath["cos"](math.pi)

# calculating: cos <- why?
print mymath["sin"](math.pi)

【问题讨论】:

【参考方案1】:

fun 的值在函数被调用时计算。

在您提供的示例中,fun 是一个全局变量,for 循环运行后它的值是“cos”。

我认为您希望在创建函数时替换 fun 的值,但事实并非如此。该函数在按预期运行时评估变量的值。

这与你定义函数的命名空间无关,而是你运行函数的命名空间。

import math

mymath = dict()

for fun in ["sin", "cos"]:
    def _impl(val):
        print "calculating: %s" % fun
        return getattr(math, fun)(val)
    mymath[fun] = _impl


fun = 'tan'
# will print and calculate tan
print mymath["cos"](math.pi)

【讨论】:

【参考方案2】:

从此代码(按您的预期工作)

my = 

def makefun(fun):
  def _impl(x):
    print fun, x
  return _impl

for fun in ["cos", "sin"]:
  my[fun] = makefun(fun)

# will print 'cos'
my['cos'](1)
fun = 'tan'
# will print 'cos'
my['cos'](2)

似乎不是函数定义的命名空间决定了闭包的性质,而是使用的变量的命名空间。 更多测试:

my = dict()

fun = ''

def makefun():
  global fun   #This line is switched on or off
  fun = 'sin'
  def _impl(x):
    print fun, x
  return _impl

test = makefun()

#gives sin 1
test(1)
fun = 'cos'
#gives sin 2 if line global fun is used
#gives cos 2 if line global fun is NOT used
test(2)

所以正确的解释似乎是闭包保存了对其参数的引用而不是值。

【讨论】:

【参考方案3】:

我认为您正在尝试使事情变得更难: 以下是使用闭包的方法:

import math

mymath = dict()


def funcmaker(fun):
    print "creating %s function" % fun
    def calculate(val):
        print "calculating: %s" % fun
        return getattr(math, fun)(val)
    return calculate

print funcmaker("sin")(math.pi)
print funcmaker("cos")(math.pi)

上面的代码给你以下结果:

creating sin function
calculating: sin
1.22464679915e-16
creating cos function
calculating: cos
-1.0

【讨论】:

以上是关于了解 Python 闭包的主要内容,如果未能解决你的问题,请参考以下文章

草根学Python(十五) 闭包(解决一个需求了解闭包流程)

python装饰器详解

Python基础——闭包与lambda的结合

Python基础——闭包与lambda的结合

深入理解闭包中的委托

闭包简单的了解