了解 Python 闭包
Understanding Python Closures
我一直认为 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)
调用函数时计算 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)
来自这段代码(如您所愿)
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)
所以正确的解释似乎是闭包保存了对其参数的引用而不是值。
我认为你在试图让事情变得更难:
以下是使用闭包的方法:
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 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)
调用函数时计算 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)
来自这段代码(如您所愿)
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)
所以正确的解释似乎是闭包保存了对其参数的引用而不是值。
我认为你在试图让事情变得更难: 以下是使用闭包的方法:
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