目录
Python3中几种传递参数的方式:
1.位置参数
2.默认参数
3.关键字参数
4.可变参数
5.keyword-only参数
6.参考链接
我们在看代码时,除了能看到普通的定义函数的入参写法,比如 def func(param1, param2): ,可能也会看到入参用 *args, **kwargs 来代替的写法,比如 def func(*args, **kwargs):,此外还有一种写法,比如 def func(param1, *, param2):,中间多了一个单纯的星号,这个用法又是什么意思呢?先从Python中的几种传递参数的方式说起。
Python3中几种传递参数的方式:
位置参数、默认参数、关键字参数、可变参数(包括可变位置参数,可变关键字参数)、keyword-only参数(命名关键字参数)
1.位置参数
位置参数是最普通、最常见的传参方式,位置参数必须按照先后顺序传入,传入的参数和定义时的参数,一一对应,例如下面的“1”传给了param1,“2”传给了param2:
def func(param1, param2):
print("param1:", param1)
print("param2:", param2)
if __name__ == '__main__':
func(1, 2)
# 输出:
# param1: 1
# param2: 2
2.默认参数
默认参数也比较常见,函数定义时给某个参数设置默认值,调用函数时如果不传这个参数,就使用默认值,如果传了就用传入值:
def func(param1, param2=1):
print("param1:", param1)
print("param2:", param2)
if __name__ == '__main__':
print("未传入默认参数时")
func(1)
print("传入默认参数时")
func(1, 2)
# 输出:
# 未传入默认参数时
# param1: 1
# param2: 1
# 传入默认参数时
# param1: 1
# param2: 2
但是这里要注意,定义函数时如果同时有位置参数和默认参数,默认参数一定要在普通参数的后面,否则会报错如。这是Python语法规定,其实也很好理解,如果不规定顺序,像下面这个函数 def func(param1, param2=1, param3): ,如果传入2个参数,func(1, 2),这个“2”是传给param2的还是param3的会有歧义。
使用默认参数还有一个需要注意的地方,默认参数的默认值尽量使用不可变对象,param2=1、param2="txt"这种,否则会引起意想不到的问题。关于不可变对象可以参考:Python中的不可变对象和可变对象
3.关键字参数
关键字参数其实不能单独算作一类参数,是Python中比较方便的一个传参方式。就是在调用函数时,指定将哪个实参传给哪个形参,当然指定的形参名字必须是函数定义时所用的名字。其实普通的位置参数、默认参数、可变参数、keyword-only参数都可以用关键字参数的方式传参。
def func(a, b, c=3, d=4):
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
if __name__ == '__main__':
func(1, 2, 3, 4)
func(1, 2, 3, d=4)
func(1, 2, c=3, d=4)
func(1, 2, d=4, c=3)
func(1, b=2, c=3, d=4)
func(d=4, c=3, b=2, a=1)
# 输出都是:
# a: 1
# b: 2
# c: 3
# d: 4
4.可变参数
可变参数也叫动态参数,在Python标准库中见到的比较多。使用可变参数传入的参数的个数是动态的,可以是1个、2个到任意个,还可以是0个。
def func(*args, **kwargs):
print("type of args: ", type(args))
print("args:", args)
print("type of kwargs: ", type(kwargs))
print("kwargs:", kwargs)
if __name__ == '__main__':
func(1, 2, a=3, b=4)
# 输出
# type of args: <class 'tuple'>
# args: (1, 2)
# type of kwargs: <class 'dict'>
# kwargs: {'a': 3, 'b': 4}
可以看到动态参数分两种,一个是*开头,例如*args,另一个是**开头,例如**kwargs。其中args和kwargs完全可以像其他参数一样自己命名,只是约定俗成的用*args和**kwargs,使用这两个IDE也会自动联想补全。args的类型是元组,调用函数时可以传入任意多的参数,这些参数会自动封装到args里,成为一个元组。kwargs的类型是字典,调用函数时可以传入任意多的自定义键值对参数,这些参数会自动封装到kwargs里,成为一个字典。
用*args,**kwargs组合的方式理论上可以传入任意值,许多标准库代码都是这样写的,*args必须写在**kwargs前面。但是我觉得如果真的所有函数入参都这样写,代码看起来会比较难懂,还是尽量不用这种方法。
那么在函数里面args和*args,kwargs、*kwargs、**kwargs有什么区别呢?可以试一下对比看看,下图中可以看出,*号在这里只是一个标识作用,是给解释器看的,相当于把元组和字典的键的内容取出来,不用太纠结这个,就是一种规定。
同样可变参数位置参数和默认参数使用时也要注意顺序:位置参数、默认参数或*args、**kwargs。也就是说下面这两种方式都是可以的:
5.keyword-only参数
keyword-only参数是Python3中新加入的特性,比较不多见。
定义时有一个单独的*号,其实这也只是一种规定,*号看上去像是一个参数,其实它不占参数个数,是给解释器看的。规定*号后面的参数,能且只能用key=value的方式传入,也就是上面第3步那种关键字参数传参形式。
def func(a, b, *, c=3, d=4):
print("a:", a)
print("b:", b)
print("c:", c)
print("d:", d)
if __name__ == '__main__':
func(1, 2, c=3, d=4)
# 输出:
# a: 1
# b: 2
# c: 3
# d: 4
上面这个函数如果没有单独的星号,我们可以 func(1, 2, 3, 4), func(1, 2, c=3, 4), func(1, 2, c=3, d=4)这样调用,而有了这个星号标识,就只能用 func(1, 2, c=3, d=4) 这种方式调用。