最近碰到一个问题,就是函数参数类型怎么判断,是否就是我们定义函数时就已经确定了的?
def foo(a, b=0, *args, **kwargs):
print(a)
print(b)
print(args)
print(kwargs)
按照网上资料,普遍的说法
- 位置参数:a
- 默认参数:b
- 接收任意数量位置参数:args
- 接收任意数量关键字参数:kwargs
然后我也一直这么认为的,但是事情并没有这么简单,不记得因为什么开始对这个参数类型产生了疑惑,遂在网上搜索Python关键字参数等相关文章博客,主要有以下几种形式:
# **kwargs接收任意数量
def foo1(a, b=10, **kwargs):
pass
def foo2(a):
pass
def foo3(a, b=10):
pass
foo1(10, 20, c=30, d=40)
foo2(a=10)
foo3(a=10, b=10)
这个时候我就纳闷了,如果一开始函数定义时,参数类型是固定的话,那为什么有的文章里举例的时候,用到了foo(args1=value1, args2=value2,…)的这种形式,所以我不理解:关键字参数不是被**kwargs接收的么,那为什么这种形式也叫关键字参数呢? 而我问了一些人之后,有的人说参数类型怎么会因为参数传入形式不同而变化呢?(这个说法应该是有问题的)
后来我查了《Effective Python》中文版的(因为刚好在手边),第19条:用关键字参数来表达可选的行为
def foo(a, b, c=30, d=40):
pass
里面举例的时候用到了类似这种形式的函数(简写了函数名称及参数名称),foo(10,20, c=300, d=400)
这种调用方式,这里c、d书里说这两个是可选的关键字参数
看到这里,我明确了一点:关键字参数应该不是由**kwargs这种接收方式所决定的
1、函数参数可以按位置或关键字来指定
2、…可以使用带有默认值的关键字参数…
3、python函数中的所有位置参数,都可以按关键字传递
- 引用块内容
def foo(a, b):
print(a)
print(b)
foo(b=10, 10)
# foo(b=10, 10)
# ^
#SyntaxError: positional argument follows keyword argument
foo(a=10, 10)
# foo(a=10, 10)
# ^
#SyntaxError: positional argument follows keyword argument
foo(c=10, 10)
# foo(c=10, 10)
# ^
#SyntaxError: positional argument follows keyword argument
看到这里,有以下几个可以确认的:
- 函数参数有两种传入方式:
a、按位置/按关键字,其中按位置就是从前往后,依次接收传入的参数;
b、而按关键字就是key=value这种形式,这种情况就是指定将value传给指定的key,如果原函数参数有**kwargs表达式的话,那key可以在原函数中不存在,反之如果没有**kwargs接收,那就会报错了 - 关键字参数后不能有位置参数,如上面几个调用形式foo(c=10, 10),解释器报错时,这条提示信息的优先级高于
foo(c=10,d=10) # TypeError: foo() got an unexpected keyword argument 'c'
这个错误 - **kwargs =/= 关键字参数,kwargs只是用来接收关键字参数,也就是这种(key=value)形式的参数
- 当一个参数在前面按位置接收了一个对象后,后面接着以key=value第二次传入对象时,这里就会报错
foo(10, a=10) #TypeError: foo() got multiple values for argument 'a'
下面有几个大胆的推测(尚不确定):
- 函数定义时的参数(a, b=10, *args, **kwargs)应该只是用来接受参数的(“容器”)
- 参数类型是和传入方式有关系的,以key=value形式传入应该都是关键字参数
《Python Cookbook 3》中有一个例子-强制接收关键字
# python3,据说python2不支持,拥抱python3,和python2saygoodbye吧!
def foo(a, b, *, c, d):
pass
foo(10, b=10, ... , c=30, d=40)
这个例子里面,调用函数时传入的参数(c、d)必须以key=value的形式传入,所以前面的推测应该是对的
总结:
1、函数定义时定义的是参数名称,不是参数类型,参数类型是由传入方式决定的
2、默认参数也叫可选关键字参数,这种类型比较特殊,因为一开始函数定义时就以key=value的形式让key指向value了
3、知道怎么处理参数就好了,对这些概念不要过于纠结
4、以上内容只是个人想法,可能有的地方理解错误,希望知道的网友能指点迷津