前言:python中函数参数的传递是通过赋值来传递的。函数的参数有两个方面值得注意:
1.函数参数是如何定义的
2.在调用函数的过程中参数是如何被解析的
文章目录
python函数参数的定义方式
func(arg1, arg2, …)
这是最常见的定义方式,一个函数可以定义任意个参数,每个参数间用逗号分割,用这种方式定义的函数在调用的的时候也必须在函数名后的小括号里提供个数相等的值,也就是说在这种调用方式中,形参和实参的个数必须一致,而且必须一一对应,也就是说第一个形参对应这第一个实参。例 如:
def func(x, y):
print x,y
调用该函数,func(1,2)则x取1,y取2,形参与实参相对应,func(y=2, x=1)也会达到相同的效果;但如果func(1)或者func(1,2,3)则会报错。
func(arg1, arg2=value2, …)
这种函数定义方式相对于第一种,提供了默认参数,也就是在调用该函数时,可以不用给默认参数传参。例如:
def func(x, y=3):
print x,y
调用该函数,func(1,2)同样还是x取1,y取2,但是如果func(1),则不会报错了,这个时候x还是1,y则为默认的3。同第一种一样,也可以更换参数位置,比如func(y=8, x=3)用这种形式也是可以的。
func(*args) —— 不定长位置参数函数
上面两种方式是有多少个形参,就传进去多少个实参,但有时候会不确定有多少个参数,则此时第三种方式就比较有用,它以一个*加上形参名的方式来表示这个函数的实参个数不定,可能为0个也可能为多个。注意一点是,不管有多少个,在函数内部都被存放在以形参名为标识符的tuple中。例如:
def func1(*args):
if len(args) == 0:
print('args: None')
else:
print('args:', args)
func1() >> args: None
func1(1, 2, 3) >> args:(1, 2, 3)
func1(x=1,y=2,z=3) >> TypeError: func1() got an unexpected keyword argument 'x'
func(**kwargs) —— 不定长关键字参数函数
最后一种方式是形参前面加两个星号,参数在函数内部将被存放在以形参名为标识符的字典中,这时调用函数的方法则需要采用arg1=value1,arg2=value2这样的形式。例如:
def func1(**args):
if len(args) == 0:
print('args: None')
else:
print('args:', args)
func1() >> args: None
func1(x=1, y=2, z=3) >> args: {'x': 1, 'y': 2, 'z': 3}
func1(1, 2, 3) >> TypeError: func1() takes 0 positional arguments but 3 were given
python函数参数的解析方式
python函数参数的解析方式按照之前定义的四种方法优先级依次降低,先1,后2,再3,最后4;也就是先把方式1中的arg解析,然后解析方式2中的arg=value,再解析方式3,即是把多出来的arg这种形式的实参组成个tuple传进去,最后把剩下的key=value这种形式的实参组成一个dictionary传给带俩个星号的形参,也就方式4。例如:
def func_test(w, x=1, *y, **z):
print(w, x, y, z)
func_test(1) >> 1 1 () {}
func_test(1,2) >> 1 2 () {}
func_test(1,2,3) >> 1 2 (3,) {}
func_test(1,2,3,4) >> 1 2 (3, 4) {}
func_test(w=1,x=2) >> 1 2 () {}
func_test(w=1,y=2) >> 1 1 () {'y': 2}
func_test(1,2,3,y=4) >> 1 2 (3,) {'y': 4}
func_test(1,2,3,x=4) >> TypeError: func_test() got multiple values for argument 'x'
def foo(*args, **kwarg):
for item in args:
print(item)
for k,v in kwarg.items():
print(k,v)
print(30*'=')
if __name__ == '__main__':
v1 = (1, 2, 3)
v2 = [4, 5, 6]
d = {'a':11, 'b':12}
foo(v1, d)
foo(*v1, **d)
foo(v2, d)
foo(*v2, **d)
结果如下:
(1, 2, 3)
{'a': 11, 'b': 12}
==============================
1
2
3
a 11
b 12
==============================
[4, 5, 6]
{'a': 11, 'b': 12}
==============================
4
5
6
a 11
b 12
==============================
上例中说明如果v1、v2、d没有加星号那么就当成了一个参数传递给了函数,如果加了星号那么就会解包后传递给函数。
注意
- 可变位置参数*args是一个元组,是不可修改的,例如:
def func(*args):
args[0] = 4
func(1, 2, 3) >> TypeError: 'tuple' object does not support item assignment
- 对于字典类型的如果只使用一个型号*那么传入的只是字典的键,例如:
def func(*args, **kwarg):
print args, kwarg
d = {'a':1, 'b':2, 'c':3}
func(*d) >> ('a', 'b', 'c') {}
func(**d) >> () {'a': 1, 'b': 2, 'c': 3}
- 可以把字典或元组类型的参数通过解析传入1类型定义的函数里面,例如:
def func(a, b):
print("a: %d, b: %d" % (a, b))
c = a-b
return c
d = {"b": 5, "a": 3}
e = (3, 5)
f = (5, 3)
def main():
i = func(**d)
print("result: %d" %i)
j = func(*e)
print("result: %d" %j)
k = func(*f)
print("result: %d" %k)
m = func(b=2, a=1)
print(m)
if __name__ == '__main__':
main()
执行结果:
a: 3, b: 5
result: -2
a: 3, b: 5
result: -2
a: 5, b: 3
result: 2
a: 1, b: 2
result: -1