函数的参数
一:形参与实参
基本概念:
形参,形式参数,指的是定义函数时,括号内定义的参数,是某种意义上的变量名。
实参,实际参数,指的是调用函数时,括号内传入的值,是某种意义上的变量值。
注意点:
实参和形参的绑定关系只有在函数调用时才会生效,调用结束后解除绑定,释放空间。调用函数,就是把实参赋值给形参的过程。
二:位置参数
位置即顺序,指的是从左到右的顺序依次定义的参数
2.1:位置形参
位置形参的特性:调用时必须为其传值,而且传入的值必须一个不多,一个不少。
# 定义函数时,按照位置顺序定义的形参 def foo(x,y,z): print(x,y,z) foo(1,2) #程序报错 foo(1,2,3,4)#程序报错 foo(1,2,3) #程序运行正常
2.2:位置实参
调用函数时,按照位置顺序定义传入的值
位置实参特性:位置实参必须与形参一一对应
3.关键字参数
在调用函数时,以key=value形式定义的实参,称为关键字实参,相当于指名道姓的为形参传值,即便是不按照顺序定义,仍然能为指定形参传值
def foo(x,y,z): print(x,y,z) foo(x=1,y=2,z=3) foo(x=1,z=2,y=3) foo(z=3,x=2,y=1) #在以关键字参数为位置形参传值时,只要按照key=value的形式,就可以不用按照顺序
4.混合参数
在调用函数时,传入的实参同时有位置实参和关键字实参:
位置实参必须放到关键字实参的前面。
必须遵循形参的规则。
不能为同一个形参重复传值
def foo(x, y, z): print(x, y, z) foo(1, 2, z=3) foo(x=1, 2, 3) foo(1, 2, y=3) foo(1, 2, z=3) foo(x=1, y=2, z=3) foo(1, x=2, y=3, z=4)
5.默认参数
在定义阶段已经为某个形参赋值,那么该形参就被称为默认参数。可以传值也可以不传值,经常需要变的参数定义成位置形参,变化较小的参数定义成默认参数
1:默认参数已有值,,可以传值也可以不用传值
def resgister(name, age, sex="male"): print(name, age, sex) resgister("egon", 18) resgister("alex", 73, "female") resgister("wxx", 45)
2:位置形参必须在默认参数的前面;
def resgister(sex="male", name, age): print(name, age, sex) resgister("alex", 73, "female") # 程序报错
3:默认参数的值,只在定义阶段赋值一次,也就是说在定义阶段默认参数已经写死了
def resgister(name, age, sex="male"): print(name, age, sex) resgister("alex", 73, "female") # 程序正常 #由程序输出判断y的值由何而来 m = 10 def foo(x, y=m): print(x, y) m = 100 foo(1)
4:默认参数的值应该设置成不可变类型
默认参数的值是可变类型
def resgister(name, hobby, l=[]): l.append(hobby) print(name, hobby, l) # 错误实例 resgister("egon", "play") # egon play ['play'] resgister("alex", "read") # alex read ['play', 'read'] resgister("wxx", "sleep") # wxx sleep ['play', 'read', 'sleep'] # 正确实例 resgister("egon", "play", []) # egon play ['play'] resgister("alex", "read", []) # alex read ['read'] resgister("wxx", "sleep", []) # wxx sleep ['sleep']
把默认参数的值设置成不可变类型
def resgister(name, hobby, l=None): if l is None: l = [] l.append(hobby) print(name, hobby, l) resgister("egon", "play") # egon play ['play'] resgister("alex", "read") # alex read ['read'] resgister("wxx", "sleep") # wxx sleep ['sleep']
对于经常需要变化的值,需要将对应的形参定义错位置形参,对于大多数情况值都一样的情况,需要将对应的形参定义成默认形参。
6.可变长参数
可变长指的是实参的个数不确定,而实参有按位置的位置实参和按关键字的关键字实参两种形式,针对这两种形式的可变长,形参对于有两种解决方案来完整的存放他们分别是*args和**kwargs:
*args:可变长度的位置形参(* 会将溢出的位置实参全部接收,然后保存成元组形式,赋值给args)
*kwargs:可变长度的关键字形参(** 会将溢出的关键字参数全部接收,然后保存成字典形式,赋值给kwargs)
*args和*kwargs主要的功能都是有*和**完成,后面的argshe kwargs都只是变量名,是什么并不重要,但是约定俗成,也就如此了。
*args是可变长的位置形参,所以也具有位置形参的一切特性,*后定义的参数必须被传值(默认参数除外),切必须以关键字形式传值。
def foo(x, y, *args, a=1, b, **kwargs): print(x, y) print(args) print(a) print(b) print(kwargs)
7.在实参中的*和**
形参中的 * 和 ** 把溢出的位置实参和关键字实参分别存成了元组和字典,那么在实参中*和**又是有什么功能呢?
实参加*,就把该实参的值打散成字符串
def foo(x,y,z): print(x,y,z) foo(*[1,2,3]) #foo(*[123]) == foo(1,2,3)
实参加**,就把该实参的值打散成关键字参数
def foo(x,y,z,**kwargs): print(x,y,z) print(kwargs) foo(1,2,3,**{"a":4,"b":5}) #foo(1,2,3,**{"a":4,"b":5}) == foo(1,2,3,a=4,b=5)
打散的关键字实参和位置实参重复
def foo(x,y,z,**kwargs): print(x,y,z) print(kwargs) foo(1,2,3,**{"x":4,"b":5}) #TypeError: foo() got multiple values for argument 'x'