一、名称空间
1、什么是名称空间
名称到对象的映射。命名空间是一个字典的实现,键为变量名,值是变量对应的值,各个命名空间是独立没有关系的,一个命名空间中不能有重名,但是不同的命名空间可以重名而没有任何影响
通俗讲:名称空间就是存放名字的地方,三种名称空间,(之前遗留的问题x=1,1存放于内存中,那名字x存放在哪里呢,名称空间正是存放名字x与1绑定关系的地方)
2、名称空间分类
全局名称空间(global):每个模块加载执行时创建的,记录了模块中定义的变量,包括模块中定义的函数、类、其他导入的模块,模块级的变量与常量
局部命名空间(local):每个函数所拥有的命名空间,记录了函数中定义的所有变量,包括函数的入参、内部定义的局部变量
内置命名空间(built-in):任何模块均可以访问,放着内置的函数和异常(比如:input,print,str,list,tuple)
3、名称空间的加载顺序
内置名称空间(程序运行前加载)-->全局命名空间(程序运行中:从上到下加载)-->局部命名空间(程序运行中:调用时才加载)
4、名称空间的取值顺序
在局部调用:局部命名空间-->全局命名空间-->内置命名空间
在全局调用:全局命名空间-->内置命名空间
综上所述,在寻找变量时,从小范围,一层一层到大范围去找寻
二、作用域
1、什么是作用域
作用域是针对变量而言,指申明的变量在程序里的可应用范围,或者称为变量的可见性
2、作用域分类
按照生效范围可以分为全局作用域和局部作用域
全局作用域:包含内置名称空间、全局名称空间,在整个文件的任意位置都能被引用,全局有效
局部作用域:局部名称空间,只能在局部范围内生效
3、查看作用域的值
locals()和globals(),他们提供了基于字典的访问局部和全局变量的方式
locals():函数会以字典类型返回当前位置的全部局部变量
globals():函数会以字典类型返回当前位置的全部全局变量
4、关键字(global与nonlocal)
global的作用:
声明一个全局变量
在局部作用域想要对全局作用域的全局变量进行修改时,需要用到global(限于字符串,数字)
def func(): global a a=2 print(a) func() print(a) """ 2 2 """
注意:对可变数据类型(list,dict,set)可以直接引用,不用通过global
li=[1,2,3] dic={'a':'b'} def change(): li.append('a') dic['q']='g' print(dic) print(li) change() print(li) print(dic) """ {'a': 'b', 'q': 'g'} [1, 2, 3, 'a'] [1, 2, 3, 'a'] {'a': 'b', 'q': 'g'} """
nonlocal的作用
不能修改全局变量
在局部作用域中,对父级作用域(或者更外层作用域非全局作用域)的变量进行引用和修改,并且引用的哪层,从哪层及以下此变量全部发生改变
def add_b(): b=42 def do_global(): b=10 print(b) def dd_nonlocal(): nonlocal b b+=20 print(b) dd_nonlocal() print(b) do_global() print(b) add_b() """ 10 30 30 42 """
三、函数名的本质
函数名本质上就是函数的内存地址
1、可以被当做值或变量引用
def func(): pass print(func) f=func #将其传给变量f print(f) """ <function func at 0x00000000005C3E18> <function func at 0x00000000005C3E18> """
2、函数可以被当做容器类型的元素存储
def func1(): print('func1') def func2(): print('func2') def func3(): print('func3') lis=[func1,func2,func3] lis[0]() lis[1]() lis[2]() """ func1 func2 func3 """
3、可以当做函数的参数和返回值
def func1(): print('func1') def func(argv): argv() return argv #func1作为返回值
f=func(func1) #func1作为参数 f() """ func1 func1 """
四、闭包
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包(即:内层函数,对外层函数(非全局)的变量的引用)
example(例子):
def func(): name='eva' def inner(): print(name) return inner f=func() f() #eva
1、检测闭包函数的公共属性:closure
如果里层的函数调用__closure__方法输出是一个cell对象,则证明是闭包
def wrapper(): name='是闭包' def inner(): print(name)#调用外层函数的变量 inner() print(inner.__closure__) wrapper() """ 是闭包 (<cell at 0x0000000001C40C48: str object at 0x00000000028657B0>,) """
2、带有参数的闭包函数
def wrapper(a):#a是外部传入的参数 b=10 def inner(a): print(a+b) return a+b inner(a) wrapper(10)#20