【python基础】第17回 函数 名称空间与作用域
本章内容概要
1. * 与 ** 在实参中的作用
2. 命名关键字参数
3. 命名空间
4. 名字的查找顺序
5. 名称空间的作用域
6. 局部名称空间复杂情况
7. global 与 nonlocal 关键字
8. 函数名的多种使用方式
本章内容详解
1. * 与 ** 在实参中的作用
1.1 * 可以用在实参中,实参中带 * ,先将 * 后的值打散成位置实参
def func(*args, **kwargs): print(args) print(kwargs) func() # () {} func([1, 2, 3, 4, 5]) # ([1, 2, 3, 4, 5],) {} l1 = [1, 2, 3, 4, 5] # 取(1, 2, 3, 4, 5) func(l1[0], l1[1], l1[2], l1[3], l1[4]) # (1, 2, 3, 4, 5) {} func(*l1) # (1, 2, 3, 4, 5) {} func(*[1, 2, 3, 4, 5]) # (1, 2, 3, 4, 5) {}

1.2 **也可以用在实参中(** 后跟的只能是字典), 实参中带 ** ,先将** 后端值 打散成关键字实参
d1 = {'username': 'jason', 'paw': 123}
func(**d1) # () {'username': 'jason', 'paw': 123}
func(usermame='jason', pwd=123) # () {'usermame': 'jason', 'pwd': 123}

2. 命名关键字参数
2.1. 需要形参在传实参的时候 必须按照关键字参数才可以
def func(a, b, *args): pass func(1, 2) func(a=1, b=2) func(1, b=222) # 需要形参在传实参的时候 必须按照关键字参数才可以 # 在形参 *args的后面 def func (a, b, *args,c): print(a, b, args, c) func(1,2,3,4,5,6) # 报错

def func(a, b, *args): pass func(1, 2) func(a=1, b=2) func(1, b=222) # 需要形参在传实参的时候 必须按照关键字参数才可以 # 在形参 *args的后面 def func(a, b, *args, c): print(a, b, args, c) # func(1, 2, 3, 4, 5, 6) # 报错 func(1, 2, 3, 4, 5, c=666) # func(1, 2, 3, 4, 5, c=666)

2.2 如果形参中还要** kwargs 那必须在他的对面
def func(a, b, *args, c, **kwargs): pass func(1, 2, 3, 4, 5, c=123, name='jason')

3. 命名空间
3.1 定义
就是用来存放变量名与数据值之间绑定关系的地方
回忆:name = 'jason'
在内存中申请一块内存空间存储jason 然后绑定变量名name,变量名name与jason的绑定关系就会被储存到名称空间中,之后使用名字都是去名称空间中查找,并锁定对应的数据值, del name 删除的不是数据值 而是变量名以及变量名与数据值之间的绑定关系
3.2 名称空间的分类
1. 内置名称空间
python解释器运行就会立刻创建的空间,写代码过程中可以直接使用的名字都在该空间中
eg: len() print() input() ...
2. 全局名称空间
py文件运行代码过程中产生的名字都会存入该空间
普通代码里面的变量名
分支结构里面的变量名
循环结构里面的变量名
定义函数的函数名
定义类的类名
3. 局部名称空间
函数2体代码运行过程中产生的名字都会存入该空间
3.3 名称空间的存活周期
1. 内置名称空间
解释器运行(创建) 解释器关闭(销毁)
2. 全局名称空间
py文件运行(创建) py文件结束(销毁)
3. 局部名称空间
函数体代码运行(创建) 函数体代码结束(销毁)
4. 名字的查找顺序
查找名字之前一定要先看自己在哪个名称空间
4.1. 当前在全局名称空间
全局名称空间 >>: 内置名称空间
4.2. 当前在局部名称空间
局部名称空间 >>: 全局名称空间 >>: 内置名称空间
名字的查找顺序默认
5. 名称空间的作用域
5.1. 内置名称空间
在程序任意位置都可以使用(全局有效)
5.2. 全局名称空间
在程序任意位置都可以使用(全局有效)
5.3. 局部名称空间
在各自的局部空间可以使用(局部有效)
6. 局部名称空间复杂情况
6.1 各自局部名称空间默认情况下不能彼此共享名字
def func1(): name = 'jason' print(age) def func2(): age = 12 print(name) func1() func2()

6.2 特殊情况 函数在定义阶段其实名字的查找顺序就已经固定好了
def func1(): x = 2 def func2(): x = 3 def func3(): x = 4 print(x) func3() func2() func1()


7. global 与 nonlocal 关键字
7.1 global
正常情况下 局部名称空间里面出现新的名字会在局部名称空间中存储,但是有时候需要在局部名称空间中修改全局名称空间的名字
money = 999 def func(): money = 1000 print(money) func() print(money)

声明 局部名称空间中的money操作的是全局的money
money = 999 def func(): global money money = 1000 print(money) func() print(money)

局部修改全局名称空间中不可变类型的数据 需要使用关键字global声明 如果是可变类型 则无需关键字声明
l1 = [1, 2, 3, 4, 5] s = '$jason$' def func(): global s s = 'jason' res = s.strip('$') l1.append(113123) l1.append(666) func() print(l1)

7.2 nonlocal
nonlocal 在内存局部名称空间修改外层局部名称空间中的不可变类型
def func1(): x = 1 l1 = [1,2] def func2(): # nonlocal x x = 999 l1.append(666) func2() print(x) print(l1) func1()

def func1(): x = 1 l1 = [1,2] def func2(): nonlocal x x = 999 l1.append(666) func2() print(x) print(l1) func1()

8. 函数名的多种使用方式
8.1 函数名也可以被用来多次赋值(函数名与变量名使用一致)
def func(): print('from func') # 1.函数名也可以被用来多次赋值(函数名与变量名使用一致) name = func name() name1 = name name1()

8.2 函数名还可以当做函数的实参
def func(): print('from func') # 2.函数名还可以当做函数的实参 def index(a): print(a) index(123) name = 'jason' index(name) index(func)

8.3 函数名还可以当做函数的返回值
def func(): print('from func') # 3.函数名还可以当做函数的返回值 def index(): return func res = index() print(res) res()

8.4 函数名还可以当作容器类型里面的数据值
def func(): print('from func') # 4.函数名还可以当做容器类型里面的数据值 l1 = [1,2,3,4,func] print(l1) l1[-1]()

作业
1.将之前的员工管理系统使用今日新的套路修改完善
# 4.定义存储用户数据的字典 data_dict = {} # {'1':{}, '2':{}, '3':{} } '''1.先封装成五个空函数''' def add_emp_info(): while True: # 5.获取用户数据 emp_id = input('请输入员工编号>>>:').strip() # 9.针对员工编号应该做不重复校验 if emp_id in data_dict: print('该员工编号已经存在') continue emp_name = input('请输入员工姓名>>>:').strip() emp_age = input('请输入员工年龄>>>:').strip() emp_job = input('请输入员工岗位>>>:').strip() emp_salary = input('请输入员工薪资>>>:').strip() # 6.构造存储用户数据的小字典 temp_dict = {} # 7.将员工数据全部录入该小字典 temp_dict['emp_id'] = emp_id temp_dict['emp_name'] = emp_name temp_dict['emp_age'] = emp_age temp_dict['emp_job'] = emp_job temp_dict['emp_salary'] = emp_salary # 8.将员工数据小字典当做大字典的值添加 data_dict[emp_id] = temp_dict # {'1':{}} break def edit_emp_salary(): while True: # 1.获取员工编号 target_emp_id = input('请输入想要修改的员工编号>>>:').strip() # 2.判断当前员工编号是否存在 if target_emp_id not in data_dict: print('当前员工编号不存在 无法修改!!!') continue # 3.根据员工编号获取该员工的详细数据(小字典) emp_data = data_dict.get(target_emp_id) # {} # 4.获取新的员工薪资 new_salary = input('请输入该员工新的薪资>>>:').strip() # 5.修改员工小字典中薪资对应的值 emp_data['emp_salary'] = new_salary # 6.将修改之后的小字典重新赋值到大字典中 data_dict[target_emp_id] = emp_data # 7.人性化提示(也可以不写) print(f'员工编号:{target_emp_id} 员工姓名:{emp_data.get("emp_name")}薪资修改成功') break def check_emp_info(): while True: # 1.获取员工编号 target_emp_id = input('请输入想要查询的员工编号>>>:').strip() # 2.判断当前编号是否存在 if target_emp_id not in data_dict: print('当前员工编号不存在') continue # 3.根据员工编号获取员工数据字典 emp_data = data_dict.get(target_emp_id) # 4.格式化输出员工数据 print(f""" --------------------emp of info------------------ 编号:{emp_data.get('emp_id')} 姓名:{emp_data.get('emp_name')} 年龄:{emp_data.get('emp_age')} 岗位:{emp_data.get('emp_job')} 薪资:{emp_data.get('emp_salary')} ------------------------------------------------- """) break def check_all_emp(): # 1.获取所有员工数据小字典 all_emp_data = data_dict.values() # [{},{},{}] # 2.循环获取每一个员工数据字典 for emp_data in all_emp_data: # {} # 4.格式化输出员工数据 print(f""" --------------------emp of info------------------ 编号:{emp_data.get('emp_id')} 姓名:{emp_data.get('emp_name')} 年龄:{emp_data.get('emp_age')} 岗位:{emp_data.get('emp_job')} 薪资:{emp_data.get('emp_salary')} ------------------------------------------------- """) def delete_emp_info(): while True: # 1.获取想要删除的员工编号 target_delete_id = input("请输入想要删除的员工编号>>>:").strip() # 2.判断员工编号是否存在 if target_delete_id not in data_dict: print('员工编号不存在') continue # 3.根据员工编号删除键值对 data_dict.pop(target_delete_id) # 4.小提示 print(f'员工编号{target_delete_id}数据删除成功') '''2.定义一个功能字典''' func_dic = { '1': add_emp_info, '2': edit_emp_salary, '3': check_emp_info, '4': check_all_emp, '5': delete_emp_info } # 1.先搭建功能框架 while True: print(""" 1.添加员工信息 2.修改员工薪资 3.查看指定员工 4.查看所有员工 5.删除员工数据 """) # 2.获取用户输入的功能编号 func_id = input('请输入功能的编号>>>:').strip() '''3.匹配功能编号''' if func_id in func_dic: '''4.根据k获取对应的v(函数名)''' func_name = func_dic.get(func_id) '''5.调用函数''' func_name() else: print('暂无该功能编号')

浙公网安备 33010602011771号