再谈python的closure闭包特性

2021年4月14日 / 694次阅读 / Last Modified 2021年5月16日
函数

python的closure特性,就是我们说的闭包,为什么是这么个奇怪的词?

closure,就是包起来的意思,python的这个特性把什么东西包起来了呢?执行环境!以下是我的理解,不一定准确。

我看到的资料说,python def定义的函数,还创建了一个scope。比如有哟个global的foo=1,定义一个函数,内部也可以有有个foo=2,相互之间是独立的。这个scope,有点像namespace的概念,但是又不完全一样。比如我们可以访问某个namespace中的foo,但是不能访问函数中定义的foo。

python的另一个特性是,可以返回一个函数对象。闭包就建立在此基础上,如果一个函数,定义在另一个函数的内部,外部的函数所拥有的变量,可以被内部函数访问,如果外部函数将内部函数作为返回值,当外部函数被调用后,在调用时外部函数内部的这些可以被内部函数访问的变量,就成了内部函数不变的执行环境。这应该就是闭包的本质!

闭包,closure,包起来的是内部函数可以独自访问的变量,内部函数被作为返回值,可以被调用执行。每一次在调用返回内部函数的外部函数的时候,外部函数提供给内部函数可访问的变量都不相同,因此也就造成了,每一个返回的内部函数,其执行环境的差异。

理解上文,请参考我上一篇谈闭包的blog:Python的闭包特性,特别是执行副本那一段!

python闭包特性,跟partial有相似,但也不完全相同,请参考:functools.partial的使用

def定义的函数,构建了一个scope,但其他的python语法并不能构建scope,比如loop,在网上看到如下一个经典的case:

flist = []

for i in range(3):
    def func(x):
        return x*i
    flist.append(func)

for f in flist:
    print f(2)

将def放在loop里面,并不能形成closure。func函数始终只是访问全局的i,因此当执行f(2)的时候,得到的结果都是4,因为loop之后,i=2。

如何修正上面的代码,使其提供闭包特性:

# avoid closures and use default args which copy on function definition
for i in range(3):
    def func(x, i=i):
        return x*i
    flist.append(func)

# or introduce an extra scope to close the value you want to keep around:
for i in range(3):
    def makefunc(i):
        def func(x):
            return x*i
        return func
    flist.append(makefunc(i))

# the second can be simplified to use a single makefunc():
def makefunc(i):
    def func(x):
        return x*i
    return func

for i in range(3):
    flist.append(makefunc(i))

# if your inner function is simple enough, lambda works as well for either option:
for i in range(3):
    flist.append(lambda x, i=i: x*i)

def makefunc(i):
    return lambda x: x*i
for i in range(3):
    flist.append(makefunc(i))

这段代码示例很精彩!

-- EOF --

本文链接:https://www.pynote.net/archives/3599

留言区

您的电子邮箱地址不会被公开。 必填项已用*标注


前一篇:
后一篇:

More


©Copyright 麦新杰 Since 2019 Python笔记

go to top