Python中的闭包-closure

版权声明:本文为博主原创文章,转载请声明出处并添加原文链接。 https://blog.csdn.net/azsx02/article/details/78430709

闭包的概念

在一个函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。

简单的说,就是某个内部函数被当做对象返回时,夹带了这个内部函数之外的变量,这就形成了一个闭包。

def logging(level):
    def say(words):
        print '{} is a outer variable'.format(level)
        print "say {0} is {1}".format(words, level) # 夹带外部变量level
    return say # 返回的是say这个函数,它夹带了它之外的level变量

say = logging('right')
say('hello') # right is a outer variable
             # say hello is right

print say.__closure__ #(<cell at 0x00000000025C7138: str object at 0x00000000025CCBE8>,)
print say.func_closure[0].cell_contents # right
  • 通过闭包,运行say(‘hello’),不仅能够完美运行say函数的功能,还可以在say函数中引用了外部的一个变量,进而可以实现更加多样化的功能。试想一下,如果外部变量不是level,而是一个函数对象呢?这里就引出了装饰器的概念。
  • 在上面的例子中,内部函数say就是闭包函数,其实闭包函数相对与普通函数会多出一个closure的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量。

Python闭包之经典的for循环问题

上个例子中,内部函数引用的外部变量是外部函数的参数,而下面这个例子,引用的是外部函数中的局部变量,它们相对于内部函数,都是外部变量,符合闭包的定义。

# 希望一次返回3个函数,分别计算1x1,2x2,3x3
# 可以用列表接收这3个函数,然后返回列表。
def count():
    fs = []
    for i in range(1, 4):
        def f():
            return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count() # 将fs中的三个f分别传递给f1,f2,f3
print(f1()), print(f2()), print(f3()) # 9 9 9

f1(), f2(), f3() 结果不应该是 1, 4, 9 吗,实际结果为什么都是 9 呢?

原因就是当 count() 函数返回了 3 个函数时,这 3 个函数所引用的变量 i 的值已经变成了 3。由于 f1、f2、f3 并没有被调用,所以,此时他们并未计算 i*i,当 f1 被调用时,i 已经变为 3 了。

如何修改?
  • 方法一

为变量 i 创建一个封闭的作用域,将i传递到封闭的作用域内,即将 i 传递给 j。

def count():
    fs = []
    for i in range(1, 4):
        def f(j):
            def g():
                return j*j
            return g
        r = f(i)
        fs.append(r)
    return fs
  • 方法二

思路比较巧妙,用到了默认参数 j 在函数定义时可以获取到 i 的值,虽然没有用到闭包,但是和方法一有异曲同工之处。

def count():
    fs = []
    for i in range(1, 4):
        def f(j=i):
            return j*j
        fs.append(f)
    return fs

猜你喜欢

转载自blog.csdn.net/azsx02/article/details/78430709
今日推荐