Python的闭包特性

2019年9月21日 / 18次阅读 / Last Modified 2019年10月11日
语法

Python有一个有点让人费解的闭包特性,这个特性的基本特征是在函数中定义嵌套函数,并且外层函数将内层嵌套的函数作为返回值!其实我理解闭包特性实现了好几个特别的功能,给Python函数提供了静态变量,实现了相同函数的不同执行副本,还有python装饰器本质上就是一个闭包。本文记录我对Python闭包特性的理解和应用考虑。

静态变量

Python函数有静态变量吗?没有。要么global,要么就是自己的局部变量,函数退出了这些局部变量就失效。静态变量这个概念来自C语言,用static申明的变量,其地址在程序的data段(永久存在),而且只能够被某个函数访问。在Python中,我们可以用闭包这个特性,实现Python版的静态变量。

def staticVar():
    times = 0
    def showTimes():
        nonlocal times
        times += 1
        print(times)
    return showTimes

f = staticVar()
f()
f()
f()
f()
f()

staticVar函数内定义了一个showTimes函数,这个函数使用nonlocal关键词申明了times不是local的变量,而是staticVar函数内的times。直接运行staticVar函数是没有什么意义的,用f来承接内嵌的showTimes函数,实际上我们要运行的,是内嵌的那个函数,现在名字成了f,然后调用f函数5次,下面是打印出来的效果:

$ python3 cc.py
1
2
3
4
5

times这个变量,就成了f函数(showTimes函数)的静态变量。

执行副本

副本这个词来自网游,用在这里,是我主观臆断的。

很多函数在执行的时候,都会依赖一些变量或标志位,函数根据这些变量或标志位来调整自己的行为,在各种if语句中走不同的分支,输出不同的结果。我们常规的做法,就是给函数不同的入参,或者在函数执行前,先调整全局变量或标志位的值。Python的闭包,给了另外一种选择。

def createRunEnv(location=None):
    def run():
        print('I am running at',location)
        # do something specificly
    return run

f_Aisa = createRunEnv('Aisa')
f_Africa = createRunEnv('Africa')
f_Europe = createRunEnv('Europe')

f_Aisa()
f_Africa()
f_Europe()

createRunEnv函数返回的函数,带上了location属性。f_Aisa,f_Africa和f_Europe就是内部函数run的3个不同的副本,调用这3个函数,其内部的location参数是不同的。以上代码执行如下:

$ python3 fb.py
I am running at Aisa
I am running at Africa
I am running at Europe

这种函数副本的好处是,我理解也是封装。将一些参数封装起来,在创建副本的时候确定值,在执行时,只有副本可以访问,以确定自己的运行环境。对同一个函数的不同的执行环境进行打包封装!

以上介绍Python闭包带来的静态变量和函数副本的功能,其实从逻辑上看,没有闭包也可以实现(C语言什么不能实现)。只是有了闭包后,Python代码的书写更加灵活,使用这些特性,代码看起来更加清爽迷人,封装的更加优雅炫酷,当然前提是要能理解这些语法特性。如果传入闭包的参数中有函数,这就是装饰器的本质。

-- EOF --

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

留言区

《Python的闭包特性》有2条留言

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

  • 麦新杰

    给函数封装独立静态变量,给函数设置执行环境,在函数执行前后增加更多的操作(装饰器),这些都是闭包的作用。 [回复]

  • 麦新杰

    外层函数返回内部嵌套函数,这时外层函数的局部空间中被使用的变量引用的引用还存在,因此Python不会将他们的空间回收。Python的变量都是一个引用,其引用的地址控件,按照C语言的逻辑来理解,都在heap中,而不在调用栈中。函数退出,消失的仅仅是调用栈中的引用本身(引用数减少1)。 [回复]


前一篇:
后一篇:

More

麦新杰的Python笔记

Ctrl+D 收藏本页


©Copyright 麦新杰 Since 2019 Python笔记

go to top