问题:在函数调用中,星号运算符是什么意思?
*
运算符在Python中是什么意思,例如likezip(*x)
或代码f(**k)
?
- 在解释器内部如何处理?
- 它会影响性能吗?是快还是慢?
- 什么时候有用,什么时候没有?
- 应该在函数声明中还是在调用中使用它?
回答 0
单颗星*
将序列/集合解压缩为位置参数,因此您可以执行以下操作:
def sum(a, b):
return a + b
values = (1, 2)
s = sum(*values)
这将打开元组的包装,使其实际执行为:
s = sum(1, 2)
双星**
只使用字典并因此命名参数来做同样的事情:
values = { 'a': 1, 'b': 2 }
s = sum(**values)
您还可以结合:
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)
另请参见Python文档的4.7.4-解包参数列表。
另外,您可以定义要接受的函数*x
和**y
参数,这使函数可以接受在声明中未专门命名的任何数量的位置和/或命名参数。
例:
def sum(*values):
s = 0
for v in values:
s = s + v
return s
s = sum(1, 2, 3, 4, 5)
或搭配**
:
def get_a(**values):
return values['a']
s = get_a(a=1, b=2) # returns 1
这可以使您无需声明它们即可指定大量可选参数。
再一次,您可以结合:
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
一点:这些不是运算符。表达式中使用运算符从现有值创建新值(例如1 + 2变为3。这里的*和**是函数声明和调用语法的一部分。
回答 2
对于要“存储”函数调用的情况,我发现这特别有用。
例如,假设我对功能“ 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])之类的丑陋操作外,没有其他方法可以调用add。另外,如果变量数量可变,则所有需要的if语句的代码都会变得很丑陋。
另一个有用的地方是定义Factory对象(为您创建对象的对象)。假设您有一些工厂类,该类使Car对象返回。您可以使myFactory.make_car(’red’,’bmw’,’335ix’)创建Car(’red’,’bmw’,’335ix’),然后返回它。
def make_car(*args):
return Car(*args)
当您要调用超类的构造函数时,这也很有用。
回答 3
它称为扩展调用语法。从文档中:
如果语法* expression出现在函数调用中,则表达式必须计算为序列。来自此序列的元素被视为它们是附加的位置参数。如果存在位置参数x1,…,xN,并且表达式的计算结果为序列y1,…,yM,则等效于使用M + N个位置参数x1,…,xN,y1,…的调用。 ..,yM。
和:
如果语法** expression出现在函数调用中,则expression必须计算为一个映射,该映射的内容被视为其他关键字参数。如果关键字同时出现在表达式中并作为显式关键字参数出现,则会引发TypeError异常。
回答 4
在函数调用中,单星号将列表变成单独的参数(例如zip(*x)
,与zip(x1,x2,x3)
if相同x=[x1,x2,x3]
),而双星号将字典变成单独的关键字参数(例如f(**k)
,与f(x=my_x, y=my_y)
if相同)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}
)”。