14---函数的参数
一。形参和实参
# 形参(形式参数)和实参(实际参数)
# 形参:再定义函数阶段定义的参数称之为形式参数,简称形参,相当于变量名
def fun(x,y):
print(x,y)
# 实参:在调用函数阶段传入的值称为实际参数,简称实参,相当于变量值
fun(1,2)
# 形参与实参的关系:
# 在调用阶段,实参(变量值的内存地址)的值绑定给形参(变量名)
# 这种绑定关系只能在函数体内使用
# 实参与形参的绑定关系在函数调用时生效,在函数调用结束后,解除绑定关系
# 实参相当于值,值可以是以下形式
# 形式一
fun(1,2)
# 形式二
a = 1
b = 1
fun(a,b)
# 形式三
fun(int('1'),2)
fun(fun(2,3),2)
二。形参具体使用
# 形参:定义函数阶段时的参数(变量名) # 位置形参:必须被传值(变量值),多一个不行少一个也不行 def add(x,y): print(x,y) add(1,2)
# 默认形参:在定义函数时被赋值的形参,准确的说是被赋予值的内存地址 # 默认参数不传值的情况下,使用定义函数时的值 def add(x,y=2): print(x,y) add(1) # 默认参数传值的情况下,使用调用函数时传的值 def add(x,y=2): print(x,y) add(1,4)
注意:虽然默认值可以被指定为任意数据类型,但是不推荐使用可变类型# 函数最理想的状态:函数的调用只跟函数本身有关系,不外界代码的影响
# 总结: 位置形参与默认形参混用:
# 位置形参必须在默认形参的左边
# 默认参数最开始的值是在函数定义阶段被赋值的
三。实参具体使用
# 实参:函数调用阶段的参数(变量值)
# 位置实参:在函数调用阶段,按照从左到右的顺序依次给形参传值
# 特点:实参与形参一一对应,多一个不行少一个不行
def add(x,y):
print(x,y)
add(1,2)
add(2,1)
# 关键字实参:在函数调用阶段,按照key=value的形式给形参传值
# 特点:指名道姓给某个形参传值,可以完全不参照顺序
def add(x,y):
print(x, y)
add(x=1,y=2)
add(y=2,x=1)
# 总结:关键字实参一定要在位置实参之后
# 不能对同一个形参重复赋值
四。形参与实参的关系
1、在调用阶段,实参(变量值)会绑定给形参(变量名)
2、这种绑定关系只能在函数体内使用
3、实参与形参的绑定关系在函数调用时生效,函数调用结束后解除绑定关系
五。不定长位置参数和不定长关键字参数
1/不定长位置参数*args
# 不定长位置形参*argsⅠ:定义函数阶段:*形参,用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式然后赋值紧跟其后的形参名
# *后跟的可以是任意名字,但是约定俗成应该是args
def fun(x,y,*args):
print(x,y,args)
fun(1,2,3,4,5,6)
Ⅱ:调用阶段:在实参中带*
# 实参中有*,先将*后的实参打散成位置实参,相当于调用for循环
def fun(x,y):
print(x,y)
fun(*[1,2])
Ⅲ:定义阶段和调用阶段都有不定长位置参数*args
# 将实参*后的值打散成位置参数,按照位置传给形参,溢出的用定义函数时的不定长位置参数*args接收打包成元组
def fun(x,y,*args):
print(x,y,args)
fun(*'hello')
2\不定长关键字参数**kwargs
# 不定长关键字参数**kwargs
# Ⅰ:定义函数阶段:**形参,用来接收溢出的关键字实参,溢出的关键字实参会被**保存成字典的格式然后赋值紧跟其后的形参名
**后跟的可以是任意名字,但是约定俗成应该是kargs
def fun(x,y,**kargs):
print(x,y,kargs)
fun(1,2,a=5,b=2)
# Ⅱ:调用阶段:在实参中带**
# 实参中有**,先将**后的实参打散成关键字
def fun(x, y):
print(x, y)
# fun(*{'k1':12,'k2':13}) 一个*是把字典的key传给形参
fun(**{'x':12,'y':13})
# 用两个星号给不定长关键字传值时,字典的key必须和函数的形参一致
# # Ⅲ:定义阶段和调用阶段都有不定长关键字参数**kwargs
# # 将实参**后的值打散成关键字参数,传给形参,溢出的用定义函数时的不定长关键字参数**kwargs接收打包成字典
def fun(x, y, **kwargs):
print(x, y, kwargs)
fun(**{'a':1,'x':2,'y':5,'v':'789'})
强调:混用*与**:*args必须在**kwargs之前
# def func(x,*args,**kwargs):
# print(args)
# print(kwargs)
#
# func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)
3/不定长参数的应用
# 问题由来
def index(x, y):
print('...', x, y, z)
def wrapper(a,b,c):
index(a,b,c)
wrapper(1,2,3)
第一步:调用wrapper函数,将实参1 2 3分别赋值给形参a,b,c
第二步:此时a=1,b=2,c=3
第三步:在wrapper函数内部调用index函数,将a,b,c分别赋值给xyz
第四步:此时x=a=1,y=b=2,z=c=3
第五步:执行index函数内的代码
分析:1/因为在调用wrapper函数,会间接的调用index函数
2/在调用index函数的时候,需要给三个形参传值
3/index函数是通过wrapper函数间接调用的,所以需要通过wrapper间接为index的形参传实参
4/所以wrapper函数的形参个数受到index函数的形参个数的限制
问题就是:如果修改了index的形参个数,那么相应的就要修改wrapper的形参个数,即牵一发而动全身,很麻烦
解决方式
将wrapper函数的形参定义为不定长位置形参和不定长关键字形参
所以在间接引用index函数的时候,就根据index形参的个数进行传参即可,当index函数形参个数发生变化时,wrapper函数无需进行改动
def index(x, y, z):
print('...', x, y, z)
def wrapper(*args, **kwargs):
index(*args, **kwargs)
wrapper(1, y=2, z=3)
# 第一步:调用函数wrapper
# 第二部:位置实参1传给不定长位置形参*args==>args = (1,)
# 关键字实参y=2,z=3传给不定长关键字参数==》kwargs={'y':2,'z':3}
# 第三步:间接调用index函数,发现实参是*args,**kwargs,先将args和kwargs打散成位置实参和关键字实参即 index(1,y=2,z=3)
# 第四步:将打散后的实参通过index函数的调用传给index函数的形参
# 这样不需要改动wrapper函数,就可以按照index函数的形参个数进行传值