实例详解实例详解Python装饰器与闭包装饰器与闭包
闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。本文主要给大家介绍Python
装饰器与闭包的相关知识,需要的朋友可以参考下
闭包是Python装饰器的基础。要理解闭包,先要了解Python中的变量作用域规则。
变量作用域规则变量作用域规则
首先,在函数中是能访问全局变量的:
>>> a = 'global var'
>>> def foo():
print(a)
>>> foo()
global var
然后,在一个嵌套函数中,内层函数能够访问在外层函数中定义的局部变量:
>>> def foo():
a = 'free var'
def bar():
print(a)
return bar
>>> foo()()
free var
闭包闭包
上面的嵌套函数就是闭包。 闭包 是指延伸了作用域的函数,在其中能够访问未在函数定义体中定义的非全局变量。未在函数
定义体中定义的非全局变量一般都是在嵌套函数中出现的。
上述示例中的变量a就是一个并未在函数bar中定义的非全局变量。对于bar来说,它有个专业名字,叫做 自由变量 。
自由变量的名称可以在字节码对象中查看:
>>> bar = foo()
>>> bar.__code__.co_freevars
('a',)
自由变量的值绑定在函数的__closure__属性中:
>>> bar.__closure__
(<cell at 0x000001CB2912DF48: str object at 0x000001CB291D3D70>,)
其中保存了对应自由变量的cell对象的序列,cell对象的cell_contents属性保存了变量的值:
>>> bar.__closure__[0].cell_contents
'free var'
这与JavaScript中闭包的行为是类似的,JavaScript中嵌套函数会将外层函数的活动对象添加到它的作用域链中。但与
JavaScript不同的是,当Python函数中的全局变量或者自由变量是不可变对象(数字、字符串、元组等)时,是只能读取,无法
更新的:
>>> a = 1
>>> def foo():
print(a)
a += 1
>>> foo()
UnboundLocalError: local variable 'a' referenced before assignment
>>> def foo():
a = 1
def bar():
print(a)
a += 1
return bar
>>> foo()()
UnboundLocalError: local variable 'a' referenced before assignment
两种情况下,都会报错。这并不是缺陷,而是Python的设计选择。Python不要求声明变量,但是会假定在函数定义体中赋值
的变量是局部变量,以避免在不知情的情况下修改全局变量。