1、形参与实参是什么?
形参(形式参数):指的是在定义函数时,括号内定义的参数,形参其实就变量名
实参(实际参数),指的是在调用函数时,括号内传入的值,实参其实就变量的值
def func(x,y): #x=10,y=11 # 定义函数时传入的值x,y是形参
print(x)
print(y)
func(10,11) # 调用函数时传入的值10,11是实参
注意:
实参值(变量的值)与形参(变量名)的绑定关系只在函数调用时才会生效/绑定
在函数调用结束后就立刻解除绑定
2、函数分两种
2.1位置参数:
位置即顺序,位置参参数指的就是按照从左到右的顺序依次定义的参数
2.1.1在定义函数时,按照位置定义的形参,称为位置形参
def foo(x,y,z):
print(x,y,z)
注意:
位置形参的特性是:在调用函数时必须为其传值,而且多一个不行,少一个也不行
foo(1,2) # 报错TypeError: foo() missing 1 required positional argument: 'z'
foo(1,2,3,4) #报错TypeError: foo() takes 3 positional arguments but 4 were given
2.1.2 在调用函数时,按照位置定义的实参,称为位置实参
注意:位置实参会与形参一一对应
2.2什么是关键字参数:
在调用函数时,按照key=value的形式定义的实参,称为关键字参数
def foo(x,y,z):
print(x,y,z)
在调用函数时,按照key=value的形式定义的实参,称为关键字参数
注意:
相当于指名道姓地为形参传值,意味着即便是不按照顺序定义,仍然能为指定的参数传值
foo(2,1,3)
foo(y=2,x=1,z=3)
foo(z=2,aaaa=1)
在调用函数时,位置实参与关键字实参可以混合使用,但必须
1:必须遵循形参的规则
foo(1,z=3,y=2)
foo(1,z=3)
2:不能为同一个形参重复传值
foo(1,x=1,y=3,z=2)
3 位置实参必须放到关键字实参的前面
foo(y=3,z=2,1)
3、 默认参数
在定义阶段,已经为某个形参赋值,那么该形参就称为默认参数
注意:
1 定义阶段已经有值,意味着调用阶段可以不传值
def register(name,age,sex='male'):
print(name,age,sex)
register('egon',18,)
register('alex',73,'female')
2 位置形参必须在默认参数的前面
def func(y=1,x): #错误
pass
3 默认参数的值只在定义阶段赋值一次,也就是说默认参数的值再定义阶段就固定死了
m=10
def foo(x,y=m): #在此阶段默认参数已经固定死了
print(x,y)
m='aaaaaaaaaaaa'
foo(1)
foo(1,11)
4 记住:默认参数的值应该设置为不可变类型
如果默认参数值为可变类型就会保存上一次存入的值
def register(name,hobby,l=[]): #name='wxx',hobby='play'
l.append(hobby) #l=['play']
print(name,l) # wxx ['play']
register('wxx','play') # wxx ['play']
register('alex','read') # alex ['read']
register('egon','music') # alex ['music']
如果必须使用可变元素作为默认参数的值可以使用如下两种方式:
1.每次传入一个空列表为值
register('wxx','play',[]) # wxx ['play']
register('alex','read',[]) # alex ['read']
register('egon','music',[]) # alex ['music']
2.可以定义为None,函数内再新建列表
def register(name,hobby,l=None):
if l is None:
l=[]
l.append(hobby) #l=['play']
print(name,l) # wxx ['play']
register('wxx','play') # wxx ['play']
register('alex','read') # alex ['read']
register('egon','music') # alex ['music']
应用:
对于经常需要变化的值,需要将对应的形参定义成位置形参
对于大多数情况值都一样的情况,需要将对应的形参定义成默认形参
4 什么是可变长度参数
可变长度指的参数的个数可以不固定,实参有按位置定义的实参和按关键字定义的实参,
所以可变长的实参指的就是按照这两种形式定义的实参个数可以不固定,
然而实参终究是要给形参传值的所以形参必须有两种对应的解决方案来分别处理以上两种形式可变长度的实参
形参:
*args 多余的位置参数会被*号接收然后存储在元祖内赋值给args
**kwargs 多余的关键字参数会被**号接收然后存储在列表内赋值给kwargs
'''
# foo(1,2)
# foo(1,2,3)
# foo(1,2,3,4)
#
# foo(x=1,y=2,)
# foo(x=1,y=2,z=3)
# foo(x=1,y=2,z=3,a=1)
# foo(x=1,y=2,z=3,a=1,b=2)
重要 混合用法
形参里包含*与**
1.*会将溢出的位置实参全部接收,然后保存成元组的形式赋值给args
def foo(x,y,z,*args): #args=(4,5,6,7,8)
print(x,y,z)
print(args)
foo(1,2,3,4,5,6,7,8,)
**会将溢出的关键字实参全部接收,然后保存成字典的形式赋值给kwargs
def foo(x,y,z,**kwargs): # kwargs={'c':3,'a':1,'b':2}
print(x,y,z)
print(kwargs)
foo(x=1,y=2,z=3,a=1,b=2,c=3)
2.实参里包含*与**
一旦碰到实参加*,就把该实参的值打散
def foo(x,y,z,*args): #args=([4,5,6,7,8],)
print(x,y,z)
print(args)
foo(1,2,3,*[4,5,6,7,8]) #foo(1,2,3,4,5,6,7,8)
foo(1,2,3,*(4,5,6,7,8)) #foo(1,2,3,4,5,6,7,8)
foo(1,2,3,*'hello') #foo(1,2,3,'h','e','l','l','o')
一旦碰到实参加**,就把该实参的值打散
def foo(x,y,z,**kwargs):
print(x,y,z)
print(kwargs)
foo(1,2,3,**{'a':1,'b':2}) #foo(1,2,3,b=2,a=1)
重要:组合使用
def index(name,age,gender):
print('welcome %s %s %s' %(name,age,gender))
def wrapper(*args,**kwargs): #args=(1,2,3),kwargs={'x':1,'y':2,'z':3}
index(*args,**kwargs)
wrapper(1,2,3,x=1,y=2,z=3)
wrapper(name='egon',age=18,gender='male')
wrapper('egon',age=18,gender='male')
wrapper('egon',18,gender='male')
wrapper('egon',18,'male')