函数篇:名称空间、名字查找顺序、作用域、函数对象、嵌套
2022.3.17学习笔记
- 名称空间
- 名称的查找顺序
- 作用域
- 函数对象
- 函数嵌套
一、名称空间
概念:其实就是存放变量名与变量值绑定关系得地方,可以理解为‘民政局’
1、内置名称空间
python解释器提前给我们定义好的如:
len()
print()
open()
...
存活周期:
python解释器运行---产生
python解释器关闭---销毁
2、全局名称空间
在py文件中编写的代码产生的名字都会存放到全局名称空间,如:
name = 'jason' # 变量名name存入全局名称空间
def index(): # 变量名index存入全局名称空间
pass
if True:
a = 1 # 变量名a存入全局名称空间
while True:
b = 2 # 变量名b存入全局名称空间
print(b)
...
存活周期:
py文件开始运行---产生
py文件运行结束---销毁
3、局部名称空间
函数体代码运行产生的变量名都存在局部名称空间,如:
def index():
x = 1 # x存入局部名称空间
存活周期:
函数体代码开始运行---产生
函数体代码运行结束---销毁
二、名字的查找顺序
我们知道名称空间是用来存放名字与值绑定关系的地方,那么要查找一个名字,要现在什么名称空间寻找呢,有没有先后顺序?
首先我们需要知道需要查找的名字目前在什么空间!
1、若在局部名称空间
查找顺序:局部名称空间>>>全局名称空间>>>内置名称空间
2、若在全程名称空间
查找顺序:全局名称空间>>>内置名称空间
那么问题来了,如果在三个名称空间都有相同的名字那么会怎么样呢?举个例子:
len = '全局空间的len'
def index():
len = '局部空间的len'
print(len) # 局部空间的len
index()
print(len) # 全局空间的len
所以还是按照我们查找名字的顺序,先看是在什么空间查找,就优先在什么空间查找。
这里还有一个例子值得推敲,注意看,这时候运行函数,结果如何
其实是f1调用f2调用f3调用f4,在f4的局部空间中有x,那么直接打印结果为:555
那么如果print(x)和x = 555 调换位置呢,结果是报错,为什么呢,看图:
三、作用域
概念:就是名称空间能够作用的范围
内置名称空间:任意阶段均可使用(全局有效)
全局名称空间:任意阶段均可使用(全局有效)
局部名称空间:一般只在局部名称空间有效(局部有效)
注意:后面可以用一些手段打破规则
1、global x
在局部修改全局的数据,表示声明要修改全局的不可变类型数据,可变类型不需要加global关键字
x = 111
def index():
x = 222 # 相当于在局部名称空间中新建了一个x = 222
那么怎么在局部修改全局的值呢,需要用到glabal关键字
global x # 这样接下来就可以修改全局的x了
x = 222
2、nonlocal x
在局部修改上一层局部的变量值,表示要修改该局部名称空间的上一层局部名称空间的数据,同样是针对不可变类型
def func():
x = 111
def index():
x = 222 # 这里也是相当于新建了一个x = 222,只在index下的局部空间有效
这里就需要用到nonlocal关键字了
nonlocal x
x = 222 # 这样就可以修改外层函数的值了
四、函数名对象(函数名的多种用法)
1、函数名当作变量名赋值
def index():
print('from function index')
res = index # 将函数名index赋值给res
print(res) # 结果为函数名index指向的内存空间
res() # 赋值后的变量名res也可以通过()调用index函数
2、函数名当作函数的实参
def index(): # 定义一个index函数
print('from index')
def func(a): # 定义一个有参函数func
print('from func')
print(a)
a() # a等待接收一个函数名实参,用以调用
func(index) # 将上面index函数名作为实参传入func函数
这样的话函数index和func就形成一个联动效应,联合使用
3、函数名当作函数的返回值
def func():
print('我是func的函数体代码')
return index
def index():
print('我是index的函数体代码')
res = func() # 用res接收func函数的返回值index
print(res) # 结果是:
'''我是func的函数体代码
函数名index的内存空间地址'''
4、函数名当作容器类型的元素
def func():
print('我是func的函数体代码')
l = [1, 2, 3, 4, 5, func]
print(l) # [1, 2, 3, 4, 5, <function func at 0x000001FF954860D0>] 可见打印出来的是func的内存地址
l[-1]() # 通过索引取值得到函数func,也可以直接加括号调用函数
五、函数的嵌套
1、嵌套调用
def index():
print('123') # 第二步
def func():
index() # 第一步
print('321') # 第三步
func() # 123 321
2、函数定义
可以通过函数套函数的方式来代替之前的多层循环嵌套,如:
def all_func(arg):
def register():
print('注册功能')
def login():
print('登录功能')
def delete():
print('删除功能')
if arg == '1':
register()
elif arg == '2':
login()
elif arg == '3':
delete()
else:
print('指令错误')
while True:
choice = input('输入指令>>>:')
all_func(choice)
这样我们的思路就会非常清晰,不是吗?
加油!




浙公网安备 33010602011771号