提问人:psihodelia 提问时间:5/27/2010 最后编辑:Karl Knechtelpsihodelia 更新时间:10/6/2023 访问量:270764
**(双星号/星号)和 *(星号/星号)在函数调用中是什么意思?
What do ** (double star/asterisk) and * (star/asterisk) mean in a function call?
问:
在像 or 这样的代码中,和 分别是什么意思?Python 如何实现这种行为,对性能有什么影响?zip(*x)
f(**k)
*
**
Смотритетакже: 将元组扩展为参数。请使用该问题来关闭 OP 需要在参数上使用 *
并且不知道它存在的问题。同样,对于使用 **
的情况,请使用 Converting Python dict to kwargs?
有关参数的补充问题,请参阅 **(双星/星号)和 *(星号/星号)对参数有什么作用?
答:
在函数调用中,单个星号将列表转换为单独的参数(例如 与给定的相同),双星将字典转换为单独的关键字参数(例如 与给定的 相同。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}
在函数定义中,情况正好相反:单星号将任意数量的参数转换为列表,双星号将任意数量的关键字参数转换为字典。例如 意思是“foo 接受任意数量的参数,它们将通过 (即如果用户调用 , 将是 )” ,意思是“bar 接受任意数量的关键字参数,它们将通过 (即如果用户调用 , 将是 )”访问。def foo(*x)
x
foo(1,2,3)
x
(1, 2, 3)
def bar(**k)
k
bar(x=42, y=23)
k
{'x': 42, 'y': 23}
它被称为扩展调用语法。从文档中:
如果语法 *expression 出现在函数调用中,则表达式的计算结果必须为序列。此序列中的元素被视为附加位置参数;如果存在位置参数 x1,...,xN,并且表达式的计算结果为序列 y1、...、yM,则等效于具有 M+N 位置参数 x1、...、xN、y1、...、yM 的调用。
和:
如果语法 **expression 出现在函数调用中,则表达式的计算结果必须转换为映射,其内容被视为附加关键字参数。如果关键字同时出现在表达式中并作为显式关键字参数出现,则会引发 TypeError 异常。
评论
apply()
单个星号将序列或集合解压缩为位置参数。假设我们有*
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 文档中教程的相关部分。
同样,并且可以用于参数。using 允许函数接受任意数量的位置参数,这些参数将被收集到单个参数中:*
**
*
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
评论
s = sum((1, 2, 3, 4, 5))
s = sum([1, 2, 3, 4, 5])
*values
我发现这对于存储函数调用的参数特别有用。
例如,假设我对函数“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,除了手动执行类似 的事情,这很丑陋。此外,如果变量数量可变,则代码可能会变得非常难看,其中包含您需要的所有 if 语句。add(test[0], test[1])
另一个有用的地方是定义 Factory 对象(为您创建对象的对象)。
假设您有某个类 Factory,它生成 Car 对象并返回它们。
你可以这样创建,然后返回它。myFactory.make_car('red', 'bmw', '335ix')
Car('red', 'bmw', '335ix')
def make_car(*args):
return Car(*args)
当您想要调用超类的构造函数时,这也很有用。
评论
*
**
[*a, b, *c]
{**d1, **d2}