不同于java那样的强类型语言,python的参数定义和调用非常灵活,因为灵活所以也非常容易混淆,刚学python时觉得已经对这块已经掌握的可以了就没怎么总结,今天看别人的代码有个地方的参数传递看的不太明白,所以还是总结一下,参考的官方文档,结合自己代码测试,文档地址:https://docs.python.org/zh-cn/3.6/tutorial/controlflow.html#more-on-defining-functions,往下拉就能看到参数部分。
python中的参数类型虽然多(位置参数/默认值参数/关键字参数/位置不定长参数/关键字不定长参数),但其实根本上只有两种类型的参数(位置参数/关键字参数)。函数定义时对不同类型的参数顺序没有太严格的要求,只要保证默认值参数在位置参数之后就行,如果有关键字不定长参数的话,要把它放到最后面,比如下面的这几种定义格式都是可以的,
第2种之所以正确是因为K-V形式的形参也可以在调用时以位置参数的形式赋值。
虽然几种不同的定义格式都是允许的,但开发中应该选择第一种。因为函数在调用时,要求实参中所有的位置参数都必须在关键字参数之前,会先拿实参中的位置参数从前到后依次为形参赋值,无论这个形参是位置参数形式还是K-V键值对形式,实参中多余的位置参数如果有不定长位置参数*args则会被作为一个元组收集起来,没有的话就会报参数不匹配错误。然后再拿实参中的关键字参数匹配形参中同名的默认值参数,多余的关键字参数如果有不定长关键字参数**kwargs则作为一个字典被收集起来,否则报参数不匹配错误。根据这个参数匹配过程,在函数定义时也应该让位置参数在前,关键字参数在后。至于两个不定长参数*args、**kwargs只是用来收集多余的参数,在传值时非必须,所以分别跟在位置参数和关键字参数的后面就可以了。
上面说这么多只需记住一点,函数定义时的参数顺序:def fun(a, *args, b=1, **kwargs),参数的类型可以没这么多,但类型之间的相对顺序要保持相同。
1.默认值参数只会在函数初始化时加载一次,这条规则在默认值为可变对象(列表、字典以及大多数类实例)时很重要。比如,下面函数每次调用时的默认列表L一直是函数第一次被调用时的默认列表L:
def f(a, L=[]):
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
输出:
[1]
[1, 2]
[1, 2, 3]
2.*args和**kwargs真正的参数名是args与kwargs,不带*号,参数名也可以自定义,只不过为了规范才用args与kwargs,方便理解。args与kwargs的类型分别为元组和字典,所以元组和字典有的属性或方法它们也都可以使用。二者在收集多余的参数值时的优先级低于位置参数赋值与关键字参数赋值,也就是收集经位置参数赋值和关键字参数赋值后多余的参数。
3.定义时形参的格式与调用时实参的格式不要求必须一样,也就是形参为位置参数实参也可以以关键字参数的形式传值,形参为关键字参数实参也可以以位置参数的形式传值。