一、 名称空间(namespace)
1. 名称空间的分类
Python中通过提供 namespace 来实现重名函数/方法、变量等信息的识别,其一共有三种 namespace,分别为:、
- local namespace: 作用范围为当前函数或者类方法
- global namespace: 作用范围为当前模块
- build-in namespace: 作用范围为所有模块
2. 名称空间的查找顺序
1. local namespace
2. global namespace
3. build-in namespace
3. 作用域
全局作用域:内置名称空间,全局名称空间
局部作用:局部名称空间
全局作用域的变量:全局有效,在任何位置都能被访问到,除非del删掉,否则会一直存活到文件执行完毕
局部作用域的变量:局部有效,只能在局部范围调用,只在函数调用时才有效,调用结束就失效
x=1000 def func(y): x=2 print(locals()) # {'x': 2, 'y': 1} 局部命名空间变量,作用于就在本函数内 print(globals()) # 全局名称空间变量:{'__package__': None, 'x': 1000, '__file__': '...', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x008059B0>, '__doc__': None, '__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, 'func': <function func at 0x0136D7C8>, '__spec__': None, '__cached__': None} func(1) print(locals()) print(globals()) print(globals() is locals()) # True locals 在函数外的全局空间中所以和globals()内容一致
二、 闭包(closure)
1. 创建闭包
在Python中创建一个闭包可以归结为以下三点:
- 闭包函数必须有内嵌函数
- 内嵌函数需要引用上一级函数namespace中的变量
- 闭包函数必须返回内嵌函数
2. 示例
形成闭包之后,闭包函数会获得一个非空的__closure__属性
__closure__属性是一个元祖,元组里面的对象为cell对象,而访问cell对象的cell_contents属性则可以得到闭包变量的当前值
x=1 y=2 def f1(): x=4 def f2(): print(x,y) return f2
f=f1() print(dir(f)) # 从结果看出f对象中包含__closure__属性 print(f.__closure__) # __closure__对应的元祖中,包含cell类型的对象 print(f.__closure__[0]) # cell类型的对象 print(f.__closure__[0].cell_contents) # cell的值 ----------------------------------------------------------------------------------- 结果: 4 2 ['__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 0x014659D0: int object at 0x1D468A00>,) <cell at 0x014659D0: int object at 0x1D468A00> 4
3. 结论
闭包的原理,当内嵌函数引用了包含它的函数(enclosing function)中的变量后,这些变量会被保存在enclosing function的__closure__属性中,成为enclosing function本身的一部分;也就是说,这些变量的生命周期会和enclosing function一样。