函数基础学习之*与**在实参中的作用、命名关键字参数(冷门)、名称空间以及名称空间分类、名字的查找顺序、名称空间的作用域、局部名称空间复杂情况、global与nonlocal关键字、函数名的多种使用方式
目录
今日内容
*与**在实参中的作用
def func(*args, **kwargs):
print(args)
print(kwargs)
'''
* 的作用:相当于是for循环拿到它后面的数据类型里面所有的值然后一次性传给函数
'''
func() # () {}
func([1, 2, 3, 4, 5, 6]) # ([1, 2, 3, 4, 5, 6],) {}
l1 = [1, 2, 3, 4, 5, 6]
func(l1[0], l1[1], l1[2], l1[3], l1[4], l1[5]) # (1,2,3,4,5,6) {}
func(*l1) # (1, 2, 3, 4, 5, 6) {}
'''
这里的*号就是将l1中的每一个数据值全部取出来,然后一次性放给了func函数,相当于变成了多个位置实参
func(1,2,3,4,5,6)
* 在实参中的作用:会将*后面的东西相当于用一个for循环取出来一次性传给函数
'''
s = 'good'
func(*s) # ('g', 'o', 'o', 'd') {}
'''func('g', 'o', 'o', 'd')'''
d = {'1': 'jason', '2': 58}
func(*d) # ('1', '2') {}
'''
如果在字典中加了*号,它相当于用一个for循环一次性将字典中的k值全部取出来放入func中
func('1','2')
'''
d1 = {'username': 'jason', 'pwd': 123}
func(**d1) # () {'username': 'jason', 'pwd': 123}
func(username='jason', pwd=123) # () {'username': 'jason', 'pwd': 123}
'''
** 只适用于字典,将字典里的键值对把它变为关键字的参数传给函数
'''
命名关键字参数(冷门知识)
需求:在传值的时候必须按照关键字的形式传值
def func(a, b, *args):
pass
'''
在使用这个函数的时候,必须至少传入俩个实参,如果给传多个数据的话也只能是位置实参,不能是关键字实参,因为单个*适用于关键字实参,俩个*才能传入关键字实参
'''
def func(a, b, *args, c):
print(a, b, *args, c)
func(1, 2, 3)
'''
需要形参在传实参的时候,必须按照关键字参数才可以
在形参*args的后面
如果形参中还有**kwargs 那必须在它的前面
'''
def func(a, b, *args, c):
print(a, b, args, c)
func(1, 2, 3, 4, 5, 6, 7) # 报错
func(1, 2, 3, 4, 5, 6, c=666)
def func(a, b, *args, c, **kwargs):
pass
名称空间
名称空间的介绍
就是用来存放变量名与数据值之间绑定关系的地方
在内存中申请一块内存空间存储jason 然后绑定变量名name
变量名name与值jason的绑定关系就会被存储到名称空间中 之后使用名字都是去名称空间中查找并锁定对应的数据值
![image-20220704172800483](https://s2.loli.net/2022/07/04/ab4vsdQq8u3ipxf.png)
del name,删除的不是数据值,而是变量名以及变量名与数据值之间的绑定关系
![image-20220704171946693](https://s2.loli.net/2022/07/04/ZCODkc7XzoUEi8I.png)
![image-20220704172556632](https://s2.loli.net/2022/07/04/Uv5C1pDbYR8PjGJ.png)
名称空间分类
内置名称空间
python解释器运行就会立即创建的空间,写代码过程中可以直接使用的名字都在该空间中,eg:len()、print()、input()......
存活周期:解释器运行(创建) 解释器关闭(销毁)
全局名称空间
py文件运行代码过程中产生的名字都会存入该空间
普通代码里面的变量名、分支结构里面的变量名、循环结构里面的变量名、定义函数的函数名
存活周期:py文件运行(创建) py文件结束(销毁)
局部名称空间
函数体代码运行过程中产生的名字都会存入该空间
存活周期:函数体代码运行(创建) 函数体代码结束(销毁)
名字的查找顺序
重点:查找名字之前自己在哪个名称空间
'''
三个名称空间都可以存名字,如果有个名字称三个空间里都有,找哪个
1.当前在全局名称空间时,先看全局名称空间里有没有,然后再看内置名称空间
2.当前在局部名称空间时,先看局部名称空间里有没有,然后再看全局名称空间,最后再看内置名称空间
3.名字的查找顺序默认情况下不能颠倒只能是,局部到全局再到内置
'''
len = '我是全局名称空间里面的len'
def func():
len = '我是局部名称空间里面的len'
print(len) # 我是局部名称空间里面的len
func()
print(len) # 我是全局名称空间里面的len
len = '我是全局名称空间里面的len'
def func():
# len = '我是局部名称空间里面的len'
print(len) # 我是全局名称空间里面的len
func()
print(len) # 我是全局名称空间里面的len
名称空间的作用域
内置名称空间:在程序任意位置都可以使用(全局有效)
全局名称空间:在程序任意位置都可以使用(全局有效)
局部名称空间:在各自的局部空间可以使用(局部有效)
局部名称空间复杂情况
x = 1
def func1():
x = 2
def func2():
x = 3
def func3():
x = 4
print(x) # 4
func3()
func2()
func1()
x = 1
def func1():
x = 2
def func2():
x = 3
def func3():
print(x) # 3
func3()
func2()
func1()
x = 1
def func1():
def func2():
def func3():
print(x) # 1
func3()
func2()
func1()
def func1():
def func2():
def func3():
print(x) # 报错
func3()
func2()
func1()
# 嵌套关系中,找值就要从当前位置一层一层向外找
![image-20220704193629563](https://s2.loli.net/2022/07/04/jTuLUzYNFQHweGB.png)
# 冷门特殊情况,
def func1():
x = 4
def func2():
x = 4
def func3():
print(x) # 1
x = 4
func3()
func2()
func1()
'''
函数在定义阶段的时候只检测语法不执行代码,但是在这个时候它已经确认了将来找名字先跟谁要,它在检测语法的时候检测到了func3中有X,但是在执行的时候是从上往下执行,此时x还没有定义出来,就只能报错
'''
global与nonlocal关键字
money = 999 # 存在了全局
def func():
money = 1000 # 此时的money对于func这个局部名称空间来说是一个新的名字,存在了自己的名称空间
func()
print(money) # 999 这里的money此时的位置是在全局名称空间里,所以找的是全局名称空间里的money
money = 999 # 存在了全局
def func():
money = 1000
print(money) # 1000
func()
print(money) # 999
'''
正常情况下 局部名称空间里面出现新的名字会在局部名称空间中存储
但是有时候需要在局部名称空间中修改全局名称空间的名字
'''
money = 999 # 存在了全局
def func():
global money # 在局部名称空间里用的money不再是局部名称空间里的,而是全局的,然后对money做的任何操作影响的是全局的money
print(money) # 1000
func()
print(money) # 999
s = '$jason$'
def func():
global s
s = 'jason'
res = s.split('$')
func()
print(s) # jason
"""
局部修改全局名称空间中不可变类型的数据 需要使用关键字global声明
如果是可
def func1():
x = 1
l1 = [1,2]
def func2():
# global x # 局部该全局
# nonlocal x
x = 999
l1.append(666)
func2()
print(x)
print(l1)
func1()
"""
nonlocal 在内存局部名称空间修改外层局部名称空间中的不可变类型
"""
函数名的多种使用方式
1.函数名可以被用来多次赋值(函数名与变量名使用一致)
name = func # 让name也指向函数func指向的那块函数体代码的内存地址
name()
name1 = name
name1() # 同样也可以调
2.函数名当做函数的实参
def index(a):
print(a)
a()
index(123)
name = 'jason'
index(name)
index(func)
3.函数名还可以当做函数的返回值
def index():
return func
res = index()
print(res)
res()
4.函数名还可以当做容器类型里面的数据值
l1 = [1,2,3,4,func]
print(l1)
l1[-1]()
作业:
def regisetr():
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 循环切割索引找到名字
data_name = info.split('|')[0]
if username == data_name:
print('用户已经存在')
break
else:
# password = input('输入密码:').strip()
# 将用户名与密码改为字符串格式
user_data = '%s|%s\n' % (username, password)
# 写入文件中
with open(r'userinfo.txt', 'a', encoding='utf8') as write_f:
write_f.write(user_data)
print(f'{username}注册成功')
return True
def login():
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
with open(r'userinfo.txt', 'r', encoding='utf8') as read_f:
for info in read_f:
# 对用户与密码进行切割
data_name, data_pwd = info.split('|')
# 判断输入是否正确
if username == data_name and password == data_pwd.rstrip('\n'):
print('登录成功')
break
else:
print('用户名或密码有误')
def back():
print('欢迎下次再来哦')
func_dict = {'1': regisetr,
'2': login,
'3': back,
}
while True:
print('''
1.用户注册功能
2.用户登录功能
3.退出
''')
funct_choice = input('请输入要执行的操作:').strip()
if funct_choice in func_dict:
func_name = func_dict.get(funct_choice)
func_name()
else:
print('没有该功能编号')