繁体   English   中英

了解Python闭包

[英]Understanding Python Closures

我一直认为Python 2.7函数引用它们所定义的范围。请考虑以下代码。 为什么第二个输出不是“计算:罪”

有没有办法修改代码,以便它按预期工作?

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM