函数参数/作用域/args/kwargs
1.参数
1.1参数基本知识
-
任意个数
-
任意类型
func("1",True)
1.2位置传参(调用函数并传入参数)
def func(a1,a2):
pass
func(1)#缺少位置参数
func(1,2,3)#多了位置参数
1.3关键字传参
def func(a1,a2):
pass
func(a2=99,a1=2)#根据形参名字传入值
1.4关键字传参和位置传参可以混合使用
注意:位置参数在前 关键字参数在后,总和参数个数要和函数参数个数相等
def func(a1,a2,a3):
pass
func(1,a2=3,a3=9)#根据形参名字传入值
func(a1=1,3,9)#报错 关键字参数在前
func(1,a1=2,a3=9)#报错 a1得到多个值
func(1,a2=0,9)#报错 关键字在前
1.5默认参数[定义]
参照open()函数
注意:如果默认值是可变类型
def func(a1,a2=9)#a2可传可不传
pass
func(1,2)#给a2传新值 覆盖默认值
func(1)#默认a2=9
1.6 万能参数(*args)—>arguments 多个参数
-
args:接受n个位置参数
-
可以接受任意类型参数,并转换为元组
-
调用时候无*
#args循环遍历每个位置参数 一个一个放入args中 并转换为元组 def func(*args): print(args) func(1) # (1,) func(1, 2, 3) # (1,2,3) func(1, 2, [1, 23], "True", "alex") func((1, 2, 3)) # 该元组作为一个单元素传入 -->元组嵌套((1,2,3),)) #(1,) # (1, 2, 3) # (1, 2, [1, 23], 'True', 'alex') # ((1, 2, 3),))
-
调用时有:直接将后面的位置参数转换为元组
def func(*args): print(args) func(*(1, 2, 3)) # 打散传入元组 变成多个变量传入args -->(1,2,3) func(*[1, 2, 3]) # args原理是 循环遍历每个元素 添加到元组中(1,2,3) #(1, 2, 3) #(1, 2, 3)
-
只能用位置传参
def func(a1,*args,a2): pass func(1,2,3,4,a2=0)#a2只能关键字传参 #a1=1 args=(2,3,4)
1.7键值万能参数(**kwargs)
-
接收任意个关键字参数
def func(**kwargs): print(kwargs) func(k1=1,k2="gao")#kwargs={"k1":1,"k2":"gao"}
-
调用时有*
def func(**kwargs): print(kwargs) func(**{"k1":1,"k2":"gao"})#kwargs=kwargs={"k1":1,"k2":"gao"}
-
调用时候无*
def func(**kwargs): print(kwargs) func(k1=1,k2="gao")#kwargs={"k1":1,"k2":"gao"}
-
只能用关键字传参
-
综合应用
def func(*args,**kwargs): print(args,kwargs) func(*[1,2,3],k1=2,k5=9,k19=999)#(1,2,3) {"k5":9,"k19":999} func(*[1,2,3],**{"k1":"1","k2":2})#(1,2,3){"k1":"1","k2":2} func(11,22,*[1,2,3],k11=333,k33="bb")#(11,22,1,2,3) {"k11":333,"k3":"bb"}
#5.看代码写结果 # def func(name,age=19,email='123@qq.com'): # pass # a. 执行 func('alex') ,判断是否可执行,如可以请问 name、age、email 的值分别是? #可行 name=alex age=19 email=123@qq.com # b. 执行 func('alex',20) ,判断是否可执行,如可以请问 name、age、email 的值分别是? #可行 name:alex age:20 email:123@qq.com # c. 执行 func('alex',20,30) ,判断是否可执行,如可以请问 name、age、email 的值分别是? #可行 name:alex age:20 email:30 # d. 执行 func('alex',email='x@qq.com') ,判断是否可执行,如可以请问 name、age、email 的值分别是? #可行 name:alex age:19 email:x@qq.com # e. 执行 func('alex',email='x@qq.com',age=99) ,判断是否可执行,如可以请问 name、age、email 的值分别是? #alex 99 x@qq.com # f. 执行 func(name='alex',99) ,判断是否可执行,如可以请问 name、age、email 的值分别是? #不可行 关键字参数在前 位置参数在后 # g. 执行 func(name='alex',99,'111@qq.com') ,判断是否可执行,如可以请问 name、age、email 的值分别是? #不可行
练习
c. 请将执行函数,并实现让args的值为 ([11,22],33) 且 kwargs的值为{'k1':'v1','k2':'v2'}
def func(*args,**kwargs):
print(args)
print(kwargs)
val=func([11,22],33,k1="v1",k2="v2")
val1=func(*[[11,22],33],k1="v1",k2="v2")
#第一种:传入多个位置参数 循环遍历加入args后 变成元组
#第二种:类似强制转换方式 tuple([[11,22],33])将*后面的转换为元组
([11, 22], 33)
{'k1': 'v1', 'k2': 'v2'}
#————————————————————————————————————————————————————————
([11, 22], 33)
{'k1': 'v1', 'k2': 'v2'}
2.作用域
2.1全局作用域
2.1局部作用域
2.3总结
-
一个函数是一个作用域
def func(): x=9 print(x) func() print(x)#报错
-
作用域中查找数据规则:优先自己作用域查找,再去自己父级作用域查找,直到找到全局作用域为止
x=10 def func(): x=9 print(x)#9 func() print(x)#10
- 注意:函数的调用顺序
x = 10 def func(): x = 8 print(x) # 8 def func2(): x = 999 print(x) # 999 print(x) # 8 func2() func() # 执行 8 8 999
# x = 10 def func(): x = 8 print(x) # 8 def func2(): x = 999 print(x) # 999 print(x) # 8 func2() # print(x) # 8 #func2函数执行完毕后 内部局部变量x被销毁掉 所以不会对自己内部的变量进行重新赋值 func() # 执行8 8 999 8
-
子作用域中只是读取或者修改【列表类型等可变类型】父级作用域的值,【默认】无法为父级的变量重新赋值 ,子作用域只是在自己内部重新开辟一块空间,为该变量赋值。但是通过添加global /nonlocal 关键字可以为父级的指定变量重新赋值
NUM=[1,2,3] def func(): #NUM.append(999)#可以修改父级可变类型的值 print(NUM)#[1,2,3,999]
-
global :找到全局作用域中的变量
name = "gao" def func(): name = "chen" print(name) # chen def func2(): global name # 找到全局变量name name = "gao_chen"#为全局变量的name重新赋值 print("val:" + name) # func2内部的name gao_chen print(name) # func 内部的chen func2() # print(name) # chen func() # 函数执行 print(name) # gao_chen 内部函数通过global修改lname的值 #chen #chen #val:gao_chen #chen #gao_chen
-
nonlocal :找到父级作用域中指定变量 ,【必须是父级作用域 不包括全局作用域】
-
如果父级(父级的父级…..)作用域中不存在 则报错
name = "gao" def func(): name = "chen" print(name) # chen def func2(): nonlocal name # 找到父级作用域的name(func中的name) name = "gao_chen" print("val:" + name) # gao_chen print(name) # chen func2() # print(name) # gao_chen func() # print(name) # gao
name = "gao" def func(): print(name) def func2(): nonlocal name #报错 可以是父级,父级的父级 但是不能是全局 name = "gao_chen" print("val:" + name) print(name) func2() print(name) func() # print(name) #SyntaxError: no binding for nonlocal 'name' found name = "gao" def func(): name = "hahahaha" print(name) # hahahaha def func2(): print("val:" + name) # val:hahahaha def inner(): nonlocal name#不报错 父级的父级的name name = "test" inner() print(name) # hahahaha func2() # 其内部函数inner()也会被func2执行 因为inner()内部定义nonlocal关键字 # 所以父级作用域的func()函数的name会被重新赋值 print(name) # test 被局部修改 func() # print(name) # gao 没有被改变 #hahahaha #hahahaha #val:hahahaha #test #gao
-
全局变量尽量大写
3.总结
-
函数类型
- def func()
- def func(a1,a2=None)
- def func(*args,**kwargs)
-
函数参数
-
形参
- def func()
- def func(a1,a2=None)
- def func(*args,**kwargs)
-
实参
-
位置传参
-
关键字传参
-
传参规则: 位置参数在前,关键字参数在后
-
默认参数
-
万能传参
-
*args:位置传参—>可传任意类型 ——>都会转为元组
- 调用函数时候有*
- 调用函数时候没有*
-
**kwargs:关键字传参——>转为字典
- 调用函数时候有*
- 调用函数时候没有*
-
-
-
-
作用域
-
局部和全局
-
一个函数一个作用域
-
作用域查找规则:
- 自己没有父级 父级再找父级,父级都没有找全局
- 自己->父级->父级->全局[读/修改(可变)]
- 子作用域内不能为父级作用域内的变量重新赋值 只能读取或者修改[可变类型]
-
重新赋值:
- global
- nonlocal
-
-
函数嵌套