【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('暂无该功能编号')

 

posted @ 2022-07-04 21:03  |相得益张|  阅读(41)  评论(0)    收藏  举报