1. 首先说说函数的作用域
(1)其中globals()函数返回的是全局变量名及其值形成的字典,如'number': [1, 2, 3]。locals()函数返回的是函数局部变量名及其值形成的字典,如'y': 0。
(2)在函数wrapperTwo()中能打印numbers的值表明:当在函数的局部作用域中找不到某个变量时,会一层一层的往外找。
2. 闭包
height = 175
weight = 130
def outer():
age = 22
name = "wzh"
def inner():
print(height, weight, name)
print(inner.__closure__) #与print(foo.__closure__)打印的内容一样
return inner
foo = outer()
foo()
print(foo.__closure__)
'''
打印的是
(<cell at 0x000001EF19660B58: function object at 0x000001EF1A07B400>,
<cell at 0x000001EF1A000438: str object at 0x000001EF1A07C570>)
'''
可以知道函数outer()将函数inner()返回赋值给foo变量,因此调用函数foo()就是调用inner()函数。
为什么调用inner()函数能够打印age的值?age变量不是只有在调用函数outer()的时候才被定义,当函数outer()执行结束后age变量不就被回收了吗?
答案就是闭包!
也就是嵌套定义在非全局作用域里面的函数能够记住它在被定义的时候它所处的封闭命名空间。
也就是返回的函数inner()其实记住了name变量的地址。可以通过查看foo的__closure__属性得出来,这个属性里面包含封闭作用域里面的值,并且只会包含被捕捉到的值,如果在outer里面还定义了其他的值,封闭作用域里面是不会有的。也就是age的值是不会被捕捉到的,而且height,weight的值也不会被捕捉到,因为它们是全局变量,不会消失。只有name的值会被放进封闭作用域。
3. 装饰器
装饰器使用了闭包这个特性,其中将函数A当做参数传入函数B,然后返回一个函数A的增强版本,即增强的(装饰的)函数C。
def outer(some_func):
def inner():
print("before some_func")
ret = some_func()
return ret + 1
return inner
def foo():
return 1
decorated = outer(foo) # 2
decorated()
'''
打印的是
before some_func
2
'''
变量decorated是函数foo()的一个装饰版本,一个加强版本。事实上如果打算写一个有用的装饰器的话,我们可能会想愿意用装饰版本完全取代原先的函数foo,这样我们总是会得到我们的“加强版”foo。想要达到这个效果,完全不需要学习新的语法,简单地赋值给变量foo就行了:
foo = outer(foo)
# 或者使用以下的写法:
@outer
def foo():
return 1
'''
foo = outer(foo)和
@outer
def foo():
return 1
的效果是一样的
'''