一、闭包:
记得:闭包的特性就是:内嵌函数会保存它引用的外围函数的变量值。
闭包概念:在一个内部函数中,对外部作用域的变量进行引用,(并且一般外部函数的返回值为内部函数),那么内部函数和被引用的变量等就被认为是闭包。
闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体,所以严格来说,闭包不是等同于函数。
闭包是种技术实现,不应该说外围函数是闭包还是内嵌函数是闭包。
用一句话说明白闭包函数,那就是:函数内在包含子函数,并最终return子函数。
而闭包函数的最大价值在于:我们可以在函数的外部(返回了内嵌函数),直接读取该函数的局部变量。
def f1():
n = 1
def f2():
n = n +1
return n
return f2
res = f1()
print(res) # 2
二、看下面的程序:
特别注意点:
1、“greeting”函数访问了非本地的变量”prefix”,根据对namespace的理解,这是完全可以的。
2、重点是:变量”prefix”并没有随着greeting_conf函数的退出而销毁,反而是生命周期得到了延长。
记录1:
在Python中,函数对象有一个__closure__属性;
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
(<cell at 0x0000000000580B28: str object at 0x0000000000DA3230>,)
<class 'cell'>
Good Morning
greeting # print(mGreeting.__name__)
通过__closure__属性看到,它对应了一个tuple,tuple的内部包含了cell类型的对象。可以得到cell的值为”Good Morning”,也就是变量”prefix”的值。
从这里可以看到闭包的原理,当内嵌函数引用了包含它的函数(enclosing function)中的变量后,这些变量会被保存在内嵌函数的__closure__属性中,成为内嵌函数本身的一部分。
记录2:
在Python中创建一个闭包可以归结为以下三点:
函数内嵌函数;
内嵌函数需要引用上一级namespace中的变量;
外围函数必须返回内嵌函数;
通过这三点,就可以创建一个闭包,Python装饰器就是使用了闭包。
网友评论