python函数参数详解
python有两种传参的方式,位置参数和关键字参数
位置参数
位置参数是基于它们的位置或顺序传递给函数的参数。这些参数是必需的,并且必须按照与函数参数列表匹配的正确顺序提供。
以下是一个示例:
def greet(name, message):
print(f"{message}, {name}!")
greet("John", "Hello") # 输出:Hello, John!
# 错误,位置参数是必须的
greet('John')
关键字参数
关键字参数是指在函数调用时使用参数名称来传递参数的一种方式。与位置参数不同,关键字参数使用参数名称和参数值的键值对来传递参数。在函数定义时,可以指定关键字参数及其默认值,如果在函数调用时没有指定某个关键字参数的值,则会使用其默认值。
以下是一个使用关键字参数的例子:
def greet(name, message="Hello"):
print(message + ", " + name)
greet('Byte Dance')
greet('Hello', 'Byte Dance')
greet(name="Byte Dance")
greet(message="Hi", name="Byte Dance")
greet(name="Byte Dance", message="Hi") #关键字参数顺序可变
在这个例子中,greet 函数有两个参数,name 和 message。message 是一个关键字参数,它有一个默认值 "Hello"。在函数调用时,我们可以通过参数名称来指定参数值。第一个函数调用中,我们只指定了 name 参数的值,使用了默认的 message 参数值。在第二个函数调用中,我们同时指定了 name 和 message 参数的值,它们的顺序没有影响。
注意,所有有默认参数值的形参必须定义在没有默认值的形参后,否则会报错,如下方示例:
#错误,a是有默认值的,b是没有默认值
def foo(a=1, b):
pass
函数调用时的传参方式
默认情况下,调用函数时参数既可以用位置参数的形式传入,也可以用关键字参数形式传参,位置参数必须在关键字参数前, 一旦使用了关键字参数,则关键字后面的所有参数必须也用关键是参数的形式传参。如下方的例子:
def standard_arg(arg):
print(arg)
standard_arg(1)
standard_arg(arg=1)
def kw_after_pos(a, b, c):
print(a, b, c)
kw_after_pos(1,2,3)
kw_after_pos(a=1, b=2, c=3)
kw_after_pos(1, b=2, c=3)
#错误,关键字参数后不能再使用位置参数
kw_after_pos(1, b=2, 3)
有些情况下,有些参数是只能用位置参数或关键字参数的一种来传参。
含有特殊形参 / 或 *
在定义函数时有2个特别的形参, / 和 * 。
/: 如果 / 出现在了形参中,则在调用函数时,/ 前的所有参数必须以位置参数的形式传入。
*: 如果 * 出现在了形参中,则在调用函数时,* 后的所有参数必须以关键字参数的形式传入。
/ 和 * 中间的参数可以以说位置参数也可以是关键字参数。如下图所示:
- 如果定义函数时,用了 / 这个形参, 则 / 前的参数只能以位置参数的方式传
def pos_only_arg(arg, /):
print(arg)
pos_only_arg(1)
# 报错
pos_only_arg(arg=1)
- 如果定义函数时,用了 * 这个形参, 则 * 后的参数只能以关键字参数的方式传参
def kwd_only_arg(*, arg):
print(arg)
kwd_only_arg(arg=1)
#报错,必须以关键字参数的方式传参
kwd_only_arg(1)
- 既有 / 又有 * 的情况, standard参数在中间,既可以以位置参数的形式,也可以以关键字参数的形式传参:
def combined_example(pos_only, /, standard, *, kwd_only):
print(pos_only, standard, kwd_only)
combined_example(1, 2, kwd_only=3)
combined_example(1, standard=2, kwd_only=3)
任意个数的参数
如果在定义参数时,使用了类似 *name这种形式的形参,则所有多余的位置参数会被打包成tuple赋值给name,通常可变参数(*name)是最后一个形参,如果不是,则所有出现在*name后面的参数必须以关键字参数的形式传参。如下方例子:
def arbitrary_args(a, b, *c):
print(f'a:{a}\nb:{b}\nc:{c}')
print('type(c):', type(c))
arbitrary_args(1, 2, 3, 4, 5, 6, 7)
同样的,还有个 **name 的形参,如果定义时使用了这个形参, 则所有多余的关键字参数会被打包成dict赋值给name,如下方例子:
def arbitrary_args(a, b, *c, **d):
print(f'a:{a}\nb:{b}\nc:{c}\nd:{d}')
print('type(d):', type(d))
arbitrary_args(1, 2, 3, 4, 5, 6, 7)
arbitrary_args(1, 2, 3, 4, 5, 6, 7, kw1=1, kw2=2)
调用函数时,用*和**解包参数
* 运算符可以用来解包列表参数,比如内置的range()函数需要单独的start和stop参数,我们有一个列表变量args=[3, 6],可以使用*运算符对参数进行解包然后传给range:
args = [3, 6]
list(range(*args)) # 等价于 list(range(3, 6))
对比 list(range(3, 6)):
** 运算符可以用来解包字典参数提供关键字参数:
def parrot(voltage, state='a stiff', action='voom'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.", end=' ')
print("E's", state, "!")
d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
parrot(**d) # 等价与 parrot(voltage='four million', state="bleedin' demised", action='VOOM')
对比parrot(voltage='four million', state="bleedin' demised", action='VOOM'):