函数基础二 -- 命名空间,作用域,闭包
1. 命名空间
1.1内置命名空间
就是python解释器一启动,就可以使用的名字存储在内置命名空间中
print() input() len() tuple list ···
内置的名字在启动解释器的时候被夹在进内存里
1.2全局命名空间
在程序从上到下被执行的过程中一次加载进内存的
放置了我们设置的所有变量名和函数名
1.3局部命名空间
是函数内部定义的名字
当调用函数的时候,才会产生这个命名空间,随着函数执行的结束,这个命名空间就消失了
在局部: 可以使用全局、内置命名空间中的名字
在全局: 可以使用内置命名空间中的名字,但是不能用在局部中使用
在内置: 不能使用局部和全局的名字
在正常情况下, 直接使用内置的名字
当我们在全局定义了和内置名字空间中同名的名字时,会使用全局的名字
(当我自己有的时候,我就不找我的上级要了)
如果自己没有,就找上一级要,上一级没有再找上一级,如果内置的命名空间都没有,就报错
局部空间的变量名字是不共享的,各局部空间是隔离的
多个函数应该拥有多个独立的局部名字空间,且不共享
Tip:
func()
func - --> 函数的内存地址
func() - - > 函数的调用
即:
函数的内存地址 + () - --> 函数的调用
2. 作用域
全局作用域 ---作用在全局 --- 内置和全局名字空间中的名字都属于全局作用域 ---使用globals()函数查看
局部作用域 ---作用在局部 --- 函数(局部名字空间中的名字属于局部作用域) ---使用locals()函数查看
a = 1 def func(): global a a += 1 func() print(a)
对于不可变数据类型,在局部可以查看全局作用域中的变量
但是不能直接修改
如果想要修改,需要在程序的一开始添加global声明
如果在一个局部(函数)内声明了一个global变量,那么这个变量在局部的所有操作将对全局的变量有效
举例:
a = 1 def func(): # global a a += 1 # 不可变数据类型的更改 func() print(a) # 结果报错:UnboundLocalError: local variable 'a' referenced before assignment(使用之前没有定义), 因为python命名空间的原因
Tip:
关于 globals()永远打印全局的名字
locals()根据locals所在位置进行输出
3. 函数的嵌套定义
def outer(): def inner(): print('inner') inner() outer()
a = 1 def outer(): a = 2 def inner(): print(a) print('inner') def inner2(): nonlocal a # 声明了一个上层局部变量(找上层离当前函数最近一层的局部变量)
a += 1 # 不可变数据类型的更改
print('inner2')
inner2()
inner()
print('**a**',a)
outer()
print('全局a',a)
# 对全局无效 # 对局部,也只是对最近的一层有影响 a = 0 def outer(): def inner(): def inner2(): nonlocal a print(a) inner2() inner() outer()
4. 函数的本质
函数名 就是第一类对象
def func(): print(123) func() # 函数名就是内存地址 func2 = func # 函数名可以赋值 func2() l = [func, func2] # 函数名可以作为容器类型的元素 print(l) def wahaha(f): f() return f qqxing = wahaha(func) # 函数名可以作为函数的参数
5. 闭包
定义 : 1. 嵌套函数 2. 内部函数调用外部函数的变量
def outer(): a = 1 def inner(): print(a) print(inner.__closure__) # 打印cell ···的内容,说明这个函数就是闭包 outer() print(outer.__closure__) # 结果: (<cell at 0x0000006FEADFC078: int object at 0x000000005E9D22D0>,) # None
闭包最常用的形式:
# 在一个函数的外部调用这个函数内部的函数 def outer(): a = 1 def inner(): print(a) return inner inn = outer() inn()
闭包实例:
from urllib.request import urlopen def get_url(): url = 'http://www.baidu.com/' # 这样每次执行,内存里不需要多次定义url,节省资源 def get(): ret = urlopen(url).read() return ret get_func = get_url() get_func()
6. 排错
出现多行错误提示,要从下往上找
如果最下边提示的是自己写的代码,那么错误就在这个地方
如果最下边提示的是系统源码,那么往上找到第一个自己代码报错处,错误就在这个地方
作用域链: