Python 星形和双星运算符在函数调用中的含义是什么?
在Python中,Python 星形和双星运算符在函数调用中的含义是什么?,python,syntax,parameter-passing,iterable-unpacking,argument-unpacking,Python,Syntax,Parameter Passing,Iterable Unpacking,Argument Unpacking,在Python中,*运算符是什么意思,例如在zip(*x)或f(**k)之类的代码中 s = sum(1, 2, c=10, d=15) 在解释器内部如何处理它 它会影响性能吗?是快还是慢 什么时候有用,什么时候不有用 它应该在函数声明或调用中使用吗 在函数调用中,单星将列表转换为单独的参数(例如zip(*x)与zip(x1,x2,x3)ifx=[x1,x2,x3]),双星将字典转换为单独的关键字参数(例如f(**k)与f(x=my_x,y=my_y)ifk={ s = sum(1, 2, c
*
运算符是什么意思,例如在zip(*x)
或f(**k)
之类的代码中
s = sum(1, 2, c=10, d=15)
在函数调用中,单星将列表转换为单独的参数(例如
zip(*x)
与zip(x1,x2,x3)
ifx=[x1,x2,x3]
),双星将字典转换为单独的关键字参数(例如f(**k)
与f(x=my_x,y=my_y)
ifk={
s = sum(1, 2, c=10, d=15)
在函数定义中,情况正好相反:单星将任意数量的参数转换为列表,双起点将任意数量的关键字参数转换为字典。例如,
def foo(*x)
表示“foo接受任意数量的参数,并且可以通过列表x访问它们(即,如果用户调用foo(1,2,3)
,x
将是[1,2,3]
),def bar(**k)
意味着“bar包含任意数量的关键字参数,它们可以通过字典k访问(即,如果用户调用bar(x=42,y=23)
,k
将是{code>{x':42,'y':23}/code>”.它被称为扩展调用语法。从:
s = sum(1, 2, c=10, d=15)
如果函数调用中出现语法*表达式,则表达式必须计算为一个序列。此序列中的元素被视为附加位置参数;如果存在位置参数x1,…,xN,且表达式计算为一个序列y1,…,yM,则这相当于使用M+N位置参数x1的调用,…,xN,y1,…,yM
s = sum(1, 2, c=10, d=15)
以及:
s = sum(1, 2, c=10, d=15)
如果语法**表达式出现在函数调用中,则表达式必须计算为映射,其内容将被视为其他关键字参数。如果关键字同时出现在表达式和显式关键字参数中,则会引发TypeError异常
s = sum(1, 2, c=10, d=15)
单星*
将序列/集合解压为位置参数,因此可以执行以下操作:
def sum(a, b):
return a + b
values = (1, 2)
s = sum(*values)
s = sum(1, 2, c=10, d=15)
这将解压元组,使其实际执行为:
s = sum(1, 2)
s = sum(1, 2, c=10, d=15)
双星**
仅使用字典和命名参数执行相同操作:
values = { 'a': 1, 'b': 2 }
s = sum(**values)
s = sum(1, 2, c=10, d=15)
您还可以组合:
def sum(a, b, c, d):
return a + b + c + d
values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)
s = sum(1, 2, c=10, d=15)
将按以下方式执行:
s = sum(1, 2, c=10, d=15)
另请参阅Python文档的一节
s = sum(1, 2, c=10, d=15)
此外,您可以定义函数以获取*x
和**y
参数,这允许函数接受声明中未明确命名的任意数量的位置参数和/或命名参数
s = sum(1, 2, c=10, d=15)
例如:
s = sum(1, 2, c=10, d=15)
def sum(*values):
s = 0
for v in values:
s = s + v
return s
s = sum(1, 2, 3, 4, 5)
或使用**
:
s = sum(1, 2, c=10, d=15)
def get_a(**values):
return values['a']
s = get_a(a=1, b=2) # returns 1
这允许您指定大量可选参数,而无需声明它们
s = sum(1, 2, c=10, d=15)
同样,您可以组合:
s = sum(1, 2, c=10, d=15)
def sum(*values, **options):
s = 0
for i in values:
s = s + i
if "neg" in options:
if options["neg"]:
s = -s
return s
s = sum(1, 2, 3, 4, 5) # returns 15
s = sum(1, 2, 3, 4, 5, neg=True) # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15
一个小点是:这些不是运算符。运算符在表达式中用于从现有值创建新值(例如,1+2变为3)。这里的*和**是函数声明和调用语法的一部分。我发现这对于“存储”函数调用特别有用
s = sum(1, 2, c=10, d=15)
例如,假设我对函数“add”进行了一些单元测试:
s = sum(1, 2, c=10, d=15)
def add(a,b):返回a+b
测试={(1,4):5,(0,0):0,(-1,3):3}
对于测试,结果为tests.items():
打印“测试:添加”,测试“=”,结果“--”,添加(*test)=结果
除了手动执行类似于add(test[0],test[1])
的操作之外,没有其他方法可以调用add。这很难看。此外,如果变量数量可变,那么代码可能会变得非常难看,包含您需要的所有if语句
s = sum(1, 2, c=10, d=15)
另一个有用的地方是定义Factory对象(为您创建对象的对象)。
假设您有一些类工厂,它生成Car对象并返回它们。
您可以将其设置为myFactory.make_car('red','bmw','335ix')
创建car('red','bmw','335ix')
,然后返回它
s = sum(1, 2, c=10, d=15)
def make_car(*args):
返回车(*args)
当您想调用超类的构造函数时,这也很有用。只需在教科书的答案中添加一个脚注-在语法支持到来之前,内置的
apply()就实现了相同的功能
function为什么需要这个,函数不能在不展开的情况下迭代提供的列表吗?当然可以,但是您必须调用它:s=sum((1,2,3,4,5))
或s=sum([1,2,3,4,5])
,*values
选项使调用看起来像是接受了许多参数,但它们被打包到函数代码的集合中。真正的好处是:如果需要可变数量的参数,您可以编写不可能的函数。例如,C的printf函数,它有1+n argu在Python中,初学者可以编写def printf(string_template,*args)并继续前进。如果(意外地:p)用一个*而不是两个*解包一个字典,会发生什么情况?它似乎做了一些事情,好像出现了一个元组,但它是什么并不那么明显。(编辑:好的,我认为答案是它只是解包键,值被丢弃)最后一个例子暗示*和**不仅在解包,而且在打包!请参阅这篇优秀的页面附录:我认为这应该用“*函数调用语法”来表达。它们不是运算符,但会让人混淆,因为有一个*
和***
运算符与此语法无关。@Ian Bicking:你说得对,参数列表中的*和**是纯语法(标记)。注:对于
s = sum(1, 2, c=10, d=15)