本篇我们学习如何使用 *args 参数定义可变函数(variadic function)。
以下示例将一个元组解包成两个变量:
x, y = 10, 20
元素 10 被赋予变量 x,元素 20 被赋予变量 y。
实际上,函数的传参也是类似:
def add(x, y): return x + y add(10, 20)
以上示例中,元素 10 被传递给变量 x,元素 20 被传递给变量 y。
同样,以下示例将元素 10 赋予变量 x,元素 20 赋予变量 y,列表 [30, 40] 赋予变量 z:
x, y, *z = 10, 20, 30, 40 print(x) print(y) print(z)
Python 函数传参也执行相同的概念,例如:
def add(x, y, *args): total = x + y for arg in args: total += arg return total result = add(10, 20, 30, 40) print(result)
函数 add 接受三个参数:x、y 以及 *args。其中 args 是一个以星号开始的特殊参数。
当我们传递位置参数 10、20、30 以及 40 时,Python 将元素 10 赋予 x,20 赋予 y,元组 (30, 40) 赋予 args。函数传参和元组解包类似,只是 args 是一个元组,而不是列表。
当函数的某个参数前面存在一个星号(*)时,表示它可以接收数量可变的参数值。用户可以给 *args 参数传递零个、一个或者多个值。
在 Python 中,类似 *args 的参数被称为可变参数(variadic parameter)。包含可变参数的函数被称为可变函数(variadic function)。
可变参数的名称不一定是 args。我们可以使用更加明确的参数名,例如 *numbers、*strings、*lists 等。按照惯例,一般使用 *args 作为可变参数的名称。
以下是一个示例:
def add(*args): print(args) add()
输出结果如下:
()
add 函数打印了一个空元组。
以下示例显示了 args 参数的类型和内容:
def add(*args): print(type(args)) print(args) add()
输出结果如下:
<class 'tuple'> ()
由于我们没有传递任何参数, add() 函数输出了一个空元组。
接下来的示例为 add() 函数传递了三个参数值:
def add(*args): print(args) add(1,2,3)
输出结果如下:
(1, 2, 3)
此时, args 参数包含了三个数字。我们可以使用下标访问每个元素:
def add(*args): print(args[0]) print(args[1]) print(args[2]) add(1, 2, 3)
另外,我们也可以使用 for 循环遍历 args 元组中的元素。以下示例演示了如何将元组中的元素进行求和:
def add(*args): total = 0 for arg in args: total += arg return total total = add(1, 2, 3) print(total)
输出结果如下:
6
如果使用了 *args 参数,不能再指定其他的位置参数。不过,可以继续使用关键字参数。
以下示例返回了错误,因为它在 *arg 参数之后使用了位置参数:
def add(x, y, *args, z): return x + y + sum(args) + z add(10, 20, 30, 40, 50)
错误信息如下:
TypeError: add() missing 1 required keyword-only argument: 'z'
为了解决这个问题,我们需要使用关键字参数调用函数:
def add(x, y, *args, z): return x + y + sum(args) + z add(10, 20, 30, 40, z=50)
以上示例中,数字 10 被赋值给 x,20 被赋值给 y,(30,40) 被赋值给 args,最后 50 被赋值给 z。
下面的 point 函数接收两个参数,返回一个字符串形式的坐标点:
def point(x, y): return f'({x},{y})'
如果我们将一个元组作为参数传递给 point 函数,将会返回错误:
a = (0, 0) origin = point(a) TypeError: point() missing 1 required positional argument: 'y'
因为元组 a 作为一个完整的对象传递给 x,不会解包成两个元素分别传递给 x 和 y。所以参数 y 缺少数据。
为了解决这个问题,我们需要在实际参数前面加上 * 运算符,例如:
def point(x, y): return f'({x},{y})' a = (0, 0) origin = point(*a) print(origin)
输出结果如下:
(0,0)
此时,函数会将元组 a 进行解包并将两个元素分别赋值给 x 和 y。