名称空间

        今日内容详细

  • *与**在实参的作用
  • 命名关键字参数
  • 名称空间
  • 作用域
  • global和nonlocal关键字
  • 函数名的多种使用

*与**在实参中的作用

*号只能跟可以被for循环的数据使用

**只能跟字典使用

def func(*args, **kwargs):
    print(args)
    print(kwargs)


# *号的作用
l1 = [1, 2, 3, 4]
func(l1)  # ([1, 2, 3, 4],)  {}
func(*l1)  # (1, 2, 3, 4)  {}
'''
如果在数据值前不加*号的话是把列表当成一个整体为一个值传进去  
而func在定义阶段没有形参只有*args,**kwargs
func就会把列表当成一个多余的位置实参 然后组织成元祖传入
而在数据值前加*号的话 那就是把列表for循环出来然后在一个一个传进去
但是func里没有形参所以会把这些数据当成多余的数据值组织成元祖在传入
'''
s = 'hello tony'
func(s)  # ('hello tony',)  {}
func(*s)  # ('h', 'e', 'l', 'l', 'o', ' ', 't', 'o', 'n', 'y')  {}
'''
字符串也是一样的如果不加*号就会把字符串当成整体为一个值传入
而如果加了*号那么就会先for循环然后在一个一个传入
'''
d = {'name': 'tony', 'age': 18}
func(d)  # ({'name': 'tony', 'age': 18},)  {}
func(*d)  # ('name', 'age')  {}
'''
只要是能被for循环的都能在数据值前加*号字典也可以
只不过字典只有k参与
'''
# **的作用
d = {'name': 'tony', 'age': 18}
func(**d)  # ()  {'name': 'tony', 'age': 18}
func(name='tony', age=18)  # ()  {'name': 'tony', 'age': 18}
'''
**号只能作用于字典
**号相当于把字典里的值变成关键字实参传值了  name = 'tony', age = 18
func(**d) 与 func(name='tony', age=18)  效果是一样的
'''

所以说可以推出*号与**号在形参与实参中的不同作用

*号与**号在形参和实参中的区别

  • 形参

*号在形参中是能够接收多余的位置参数然后组织成元祖传入值

**号在形参中是能够接收多余的关键字参数然后组织成字典传入值

  • 实参

*号在实参中是能够把容器的数据类型一个一个依次传入值

**号在实参中是能够把字典的数据类型按照关键字实参一个一个依次传入值

 

 

命名关键字参数

# 命名关键字参数就是让实参必须按关键字参数传入值

def func(a, b, *args):
    print(a, b, args)


func(1, 2, 3)  # 1 2 (3,)
func(b=1, a=2)  # 2 1 ()
func(1, b=2)  # 1 2 ()

# 在这样的情况下a和b可以是位置实参传值也可以按照关键字实参传值

def func(a, b, *args, c):
    print(a, b, args, c)


func(1,2,3,4,5,6)  # 报错
func(1, 2, 3, 4, 5, 6, c=77)  # 1 2 (3, 4, 5, 6) 77
'''
这样定义参数的话c只能按照关键字实参传值
因为如果传值时全是位置参数时只有前面两个参数会被a和b接收
然后后面的会被当做多余的位置参数组织成元祖然后赋值给args
这样就会把c给漏了就会报错
所以要把c按照关键字实参传入
'''
def func(a, b, *args, c, **kwargs):
    print(a, b, args, c, kwargs)

func(
1, 2, 3, 4, 5, c=66, d=77, e=88) # 1 2 (3, 4, 5) 66 {'d': 77, 'e': 88} # 如果形参中还有**kwargs那么就在**kwargs前面加个变量名

名称空间

名称空间就是存放变量名和变量名于数据值的绑定关系的地方  而数据值在内存空间当中

name = 'tony'
'''
就是把 name 和 name与'tony'的绑定关系 存放到名称空间当中
用的时候直接调用name即可
'''

名称空间分为三类

  •   内置名称空间
  •   全局名称空间
  •   局部名称空间

1.内置名称空间

'''
内置名称空间就是存放python自带的一些函数名和类名
'''
eg:
len()
input()
open()
...

2.全局名称空间

# 全局名称空间就是存放我们在py文件中编写的一些变量名和函数名以及类名

eg:
name = 'tony'

if True:
    age = 18

for i in range(10):
    print(i)    

def func():
    pass
'''
像上面的变量名和函数名都是存放到全局名称空间中的
普通代码中的变量名
分支结构中的变量名
循环结构中的变量名
还有定义函数的函数名
还有定义类的类名
都是存入到全局名称空间中的
'''           

3.局部名称空间

# 局部名称空间就是函数体代码运行过程中产生的变量名会存入到该空间中
eg:
def func():
    name = 'tony'
    age = 18
func()

# 像上面所写的函数 当py文件运行时调用该函数就会运行该函数的代码就会产生两个变量名 这两个变量名就会存入到局部名称空间

 

 

4.三者得到关系

4.1 三者的存活周期

内置名称空间

  当python解释器运行时创建       当关闭python解释器是销毁

全局名称空间

  当py文件运行时创建            当py文件结束时销毁

局部名称空间

  当函数体代码运行时创建          当函数体代码结束时销毁

4.2 名字的查找顺序

当要查找一个名字时一定要先看自己在哪个名称空间当中

x = 1
def func():
    x = 10
print(x)  # 1
# print(y)  # 报错
'''
这些变量名都是新产生的
当在全局空间中时会先在全局空间中查找找到就会调用
找不到就会去内置空间找如果找不到就会报错
'''
len = 1
def func():
    len = 10
    print(len)  # 10
func()
print(len)  # 1
'''
在全局空间就会现在全局空间找如果找不到才会取内置空间中找
在局部空间中时也是先在局部空间中找找到调用即可 找不到才会去全局空间中找 
如果全局空间中还找不到 才会取内置空间中找 如果还找不到就会报错
'''
x = 10
def func():
    print(x)  # 10
    print(len)  # <built-in function len>
func()
print(x)  # 10
'''
因为len这个名字在局部和全局名称空间中都没有定义 只能去内置空间中找 找到调用即可
而x在局部中没有就会去全局空间中找 找到调用即可
'''
def func1():
    x = 2
    def func2():
        print(x)
    func2()
func1()
'''
现在查找x的名字是在func2的局部空间中 因为func2中没有x的名字 因为funcx是在func1的局部空间中
所以会先去func1中查找x的名字找到即可  如果func还没找到才回去全局空间中查找
'''

所以名字查找顺序默认情况下:

1.当在全局名称空间中:

  全局名称空间  >>>    内置名称空间

2.当在局部名称空间中:

  局部名称空间  >>>  全局名称空间  >>>   内置名称空间

默认情况下查找顺序不能颠倒

4.3 作用域

1.内置名称空间

  在程序的任意位置都可以使用(全局有效)

2.全局名称空间

  在程序的任意位置都可以使用(全局有效)

3.局部名称空间

  在各自局部空间中可以使用(局部有效)

4.4局部名称空间的一些复杂情况

def func1():
    name = 'tony'
    print(age)
def func2():
    age = 18
    print(name)
func1()
func2()
# 会报错 因为局部名称空间只能在各自的局部空间中使用 默认情况下两者互不干涉

def func1():
    x = 1
    def func2():
        x = 2
        def func3():
            x = 3
            print(x)  # 3
        func3()
    func2()
func1()
'''
特殊情况下 
现在在func3中的局部名称空间下会现在func3下找 如果找不到就回去func2的局部名称空间找
如果找不到就回去func1的局部名称空间找查找 如果还找不到才会去全局名称空间中查找
如果还找不到就会去内置名称空间中查找
'''
name = 'jason'
def func():
    print(name)  # 报错
    name = 'jasonNB'
func()
'''
在函数定义阶段其实查找顺序已经固定死了
因为你在定义的时候python已经知道你的func中有name的变量
那么查找的时候 就会先一直在func的局部名称空间中查找
但是你现在func中是先打印 后定义就会报错
'''

 

 

global与nonlocal关键字

global关键字

x = 111
def func():
    x = 100

func()
print(x)  # 111
'''
正常情况下局部名称空间中出现的新的变量名 会被存储到局部名称空间中
所以局部名称空间是不能修改全局名称空间里的值的  所以就会打印111
但是有时候我们需要在局部名称空间中修改全局名称空间中的值
'''
x = 111
def func():
    global x
    x = 100

func()
print(x)  # 100

l1 = [1,2,3,4]
def func():
    l1.append(66)
func()
print(l1)  # [1, 2, 3, 4, 66]

'''
而如果想在局部名称空间中修改全局名称空间中的不可变类型时需要用到 关键字 global
但是如果是可变类型不需要用到  因为可变类型修改值的时候修改的是本身 没有产生新的值
global 就是指定一个变量名 让这个变量名可以在局部名称空间中可以修改全局名称中的值
所以函数里加入一个global关键字的时候 可以让global后面那个变量名可以再局部名称空间修改全局名称空间中的值
所以x就会打印 100
'''

nonlocal关键字

def func1():
    x = 1
    l1 = [1, 2]
    def func2():
        x = 999
        l1.append(666)
    func2()
    print(x)  # 1
    print(l1)  # [1, 2, 666]
func1()
'''
正常情况下函数嵌套中的里面那个函数产生新的变量名的时候是存储在func2中的局部空间
可变类型不考虑
所以func2中的变量名的值是改变不了func1中的值的
'''

def func1():
    x = 1
    l1 = [1,2]
    def func2():
        # nonlocal x
        x = 999
        l1.append(666)
    func2()
    print(x)
    print(l1)
func1()
'''
而我们想在func2名称空间中修改func1的值必须用到nonlocal关键字
这样就能在func2名称空间中修改到func1中的值了
不能用global关键字因为global是修改的全局名称空间
'''
x = 20
def func1():
    x = 1
    l1 = [1, 2]
    def func2():
        global x
        x = 999
        l1.append(666)
    func2()
func1()
print(x)  # 999

函数名的多种用法

1.函数名可以用来赋值

def func():
    print('from func')
func()  # from func
name = func
name()  # from func
name1 = name
name1()  # from func
'''
函数名是可以多次赋值的 因为函数名绑定的是一个内存地址 而内存地址里存放的是函数体代码
而如果想要调用函数代码只需函数名加括号即可
'''

2.函数名可以当做函数的实参

def func():
    print('from func')

def index(a):
    print(a)
    a()  # from func
# index(123)  # 123
# name = 'jason'
# index(name)  # jason
index(func)  # <function func at 0x00000190C0141E18>
# 因为函数名绑定的是一个内存地址所以传入的也是一个内存地址 然后a就可以调用func函数

3.函数名可以当函数的返回值

def func():
    print('from func')

def index():
    return func
res = index()
print(res)
res()
# index返回的是func的内存地址 然后赋值给res 所以res就可以调用func函数

4.函数名还可以当做容器类型里面的数据值

def func():
    print('from func')


l1 = [1, 2, 3, 4, func]
print(l1)  # [1, 2, 3, 4, <function func at 0x000001C541EC1E18>]
l1[-1]()  # from func
# 因为函数名绑定的是一个内存地址 所以通过索引可以调用函数func

作业

user_data_dict = {}


def register():
    while True:
        emp_id = input('请输入员工编号,输入q退出>>>:').strip()
        if emp_id == 'q':
            break
        # 2.判断员工编号是否已存在
        if emp_id in user_data_dict:
            print('员工编号已存在,无法添加')
            continue
        emp_name = input('请输入员工姓名>>>:').strip()
        emp_age = input('请输入员工年龄>>>:').strip()
        emp_post = input('请输入员工岗位>>>:').strip()
        emp_salary = input('请输入员工薪资>>>:').strip()
        # 3.创建一个小字典
        data_dict = {'emp_id': emp_id, 'emp_name': emp_name, 'emp_age': emp_age, 'emp_post': emp_post,
                     'emp_salary': emp_salary}
        # 4.存入到大字典
        user_data_dict[emp_id] = data_dict
        # 5.提示信息
        print(f'员工{emp_name}添加成功')


def amend_salary():
    target_id = input('请输入员工编号>>>:').strip()
    if target_id not in user_data_dict:
        print('员工编号不存在,无法修改')
        return
    # 提取改员工的字典
    user_dict = user_data_dict[target_id]
    # 获取新的薪资
    new_salary = input('请输入该员工新的薪资>>>:').strip()
    # 修改该员工的薪资
    user_dict['emp_salary'] = new_salary
    # 修改大字典
    user_data_dict[target_id] = user_dict
    # 提示信息
    print(f'员工编号{target_id}的薪资已修改为{new_salary}')


def check_all():
    if len(user_data_dict) == 0:
        print('没有员工信息')
    else:
        for staff in user_data_dict.values():
            print('staff info'.center(30, '*'))
            print(f"""
    员工编号:{staff.get('emp_id')}
    员工姓名:{staff.get('emp_name')}
    员工年龄:{staff.get('emp_age')}
    员工岗位:{staff.get('emp_post')}
    员工薪资:{staff.get('emp_salary')}
            """)
            print('end'.center(30, '*'))


def check_assig():
    target_id = input('请输入员工编号>>>:').strip()
    # 判断员工编号是否存在
    if target_id not in user_data_dict:
        print('员工编号不存在,无法查看')
        return
    # 提取改员工的字典
    user_dict = user_data_dict[target_id]
    # 可以for循环也可以解压赋值
    # emp_id, emp_name, emp_age, emp_post, emp_salary = user_dict.values()
    print('staff info'.center(30, '*'))
    print(f"""
              员工编号:{user_dict.get('emp_id')}
              员工姓名:{user_dict.get('emp_name')}
              员工年龄:{user_dict.get('emp_age')}
              员工岗位:{user_dict.get('emp_post')}
              员工薪资:{user_dict.get('emp_salary')}
                      """)
    print('end'.center(30, '*'))


def delete_staff():
    delete_id = input('请输入员工编号>>>:').strip()
    # 判断员工编号是否存在
    if delete_id not in user_data_dict:
        print('员工编号不存在,无法删除')
        return  # 删除
    res = user_data_dict.pop(delete_id)
    print(f'员工编号{delete_id}已删除', res)


def is_choice(choice):
    if len(choice) == 0:
        print('请输入正确功能编号')
        return True
    if not choice.isdigit():
        print('请输入数字')
        return True


func_dict = {
    '0': ['退出', None],
    '1': ['注册', register],
    '2': ['修改薪资', amend_salary],
    '3': ['查看指定员工', check_assig],
    '4': ['查看所有员工', check_all],
    '5': ['删除员工', delete_staff]
}

while True:
    for func in func_dict:
        print(func, func_dict[func][0])
    choice = input('请输入功能编号>>>:').strip()
    if is_choice(choice):
        continue
    elif choice == '0':
        print('欢迎下次继续')
        break
    elif choice in func_dict:
        func_dict[choice][1]()
    else:
        print('没有功能编号')

 

 

 

posted @ 2022-07-04 16:55  stephen_hao  阅读(47)  评论(0)    收藏  举报