在函数调用中**(双星号)和*(星号)是什么意思?
在像 zip(*x)
或 f(**k)
这样的代码中,*
和 **
分别是什么意思呢?Python 是怎么实现这种功能的?这样做对性能有什么影响呢?
另请参见:将元组展开为参数。请使用这个链接来关闭那些需要在参数上使用 *
但不知道它存在的问题。同样,对于使用 **
的情况,请使用 将 Python 字典转换为关键字参数?。
有关参数的补充问题,请参见 双星号(**)和星号(*)在参数中有什么作用?。
5 个回答
我觉得这个方法特别适合用来存储函数调用时的参数。
比如说,我有一些单元测试是针对一个叫做 'add' 的函数:
def add(a, b):
return a + b
tests = { (1,4):5, (0, 0):0, (-1, 3):3 }
for test, result in tests.items():
print('test: adding', test, '==', result, '---', add(*test) == result)
除了手动像这样调用 add(test[0], test[1])
,没有其他方法,这样看起来很麻烦。而且,如果参数的数量不固定,代码就会变得很复杂,因为你需要写很多 if 语句。
这个方法还有一个好处,就是在定义工厂对象时特别有用(工厂对象就是用来创建其他对象的对象)。假设你有一个叫做 Factory 的类,它可以创建汽车对象并返回它们。你可以让 myFactory.make_car('red', 'bmw', '335ix')
这个调用创建一个 Car('red', 'bmw', '335ix')
对象,然后返回它。
def make_car(*args):
return Car(*args)
这在你想要调用父类的构造函数时也很有用。
在调用函数的时候,单个星号(*)可以把一个列表拆分成多个独立的参数,比如说 zip(*x)
和 zip(x1, x2, x3)
是一样的,前提是 x=[x1,x2,x3]
。而双星号(**)则是把一个字典拆分成多个关键字参数,比如 f(**k)
和 f(x=my_x, y=my_y)
是一样的,假设 k = {'x':my_x, 'y':my_y}
。
在定义函数的时候,情况正好相反:单个星号会把任意数量的参数收集到一个列表里,而双星号会把任意数量的关键字参数收集到一个字典里。例如,def foo(*x)
的意思是“foo可以接收任意数量的参数,这些参数会通过 x
访问到”(也就是说,如果用户调用 foo(1,2,3)
,那么 x
就会变成 (1, 2, 3)
)。而 def bar(**k)
的意思是“bar可以接收任意数量的关键字参数,这些参数会通过 k
访问到”(也就是说,如果用户调用 bar(x=42, y=23)
,那么 k
就会变成 {'x': 42, 'y': 23}
)。
一个单独的星号 *
可以把一个序列或集合拆开,变成位置参数。假设我们有:
def add(a, b):
return a + b
values = (1, 2)
使用 *
拆包运算符,我们可以写成 s = add(*values)
,这就等同于写成 s = add(1, 2)
。
双星号 **
对字典做同样的事情,它提供命名参数的值:
values = { 'a': 1, 'b': 2 }
s = add(**values) # equivalent to add(a=1, b=2)
这两个运算符可以在同一个函数调用中使用。例如,给定:
def sum(a, b, c, d):
return a + b + c + d
values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
那么 s = add(*values1, **values2)
就等同于 s = sum(1, 2, c=10, d=15)
。
你可以查看 Python 文档中教程的 相关部分。
同样,*
和 **
也可以用在参数上。使用 *
允许一个函数接受任意数量的位置参数,这些参数会被收集到一个单独的参数中:
def add(*values):
s = 0
for v in values:
s = s + v
return s
现在当函数被调用为 s = add(1, 2, 3, 4, 5)
时,values
将会是元组 (1, 2, 3, 4, 5)
(这当然会得到结果 15
)。
同样,带有 **
的参数会接收一个 dict
:
def get_a(**values):
return values['a']
s = get_a(a=1, b=2) # returns 1
这允许我们指定很多可选参数,而不需要事先声明它们。
再说一次,这两者可以结合使用:
def add(*values, **options):
s = 0
for i in values:
s = s + i
if "neg" in options:
if options["neg"]:
s = -s
return s
s = add(1, 2, 3, 4, 5) # returns 15
s = add(1, 2, 3, 4, 5, neg=True) # returns -15
s = add(1, 2, 3, 4, 5, neg=False) # returns 15