*运算符在Python中是什么意思,比如在zip(*x)或f(**k)这样的代码中?
如何在解释器内部处理它? 它会影响性能吗?它是快还是慢? 什么时候有用,什么时候没用? 它应该用在函数声明中还是调用中?
*运算符在Python中是什么意思,比如在zip(*x)或f(**k)这样的代码中?
如何在解释器内部处理它? 它会影响性能吗?它是快还是慢? 什么时候有用,什么时候没用? 它应该用在函数声明中还是调用中?
在函数调用中,单星号将一个列表转换为单独的参数(例如,如果x=[x1,x2,x3], zip(*x)与zip(x1,x2,x3)相同),而双星号将字典转换为单独的关键字参数(例如,f(**k)与f(x=my_x, y=my_y)相同,如果k = {'x':my_x, 'y':my_y}。
In a function definition it's the other way around: the single star turns an arbitrary number of arguments into a list, and the double start turns an arbitrary number of keyword arguments into a dictionary. E.g. def foo(*x) means "foo takes an arbitrary number of arguments and they will be accessible through the list x (i.e. if the user calls foo(1,2,3), x will be [1,2,3])" and def bar(**k) means "bar takes an arbitrary number of keyword arguments and they will be accessible through the dictionary k (i.e. if the user calls bar(x=42, y=23), k will be {'x': 42, 'y': 23})".
它被称为扩展调用语法。从文档中可以看到:
如果语法*表达式出现在函数调用中,表达式必须求值为序列。这个序列中的元素被当作附加的位置参数来处理;如果有位置参数x1,…, xN,表达式求值为序列y1,…, yM,这相当于调用M+N个位置参数x1,…, xN, y1,…,,
and:
如果语法**表达式出现在函数调用中,表达式必须求值为映射,映射的内容被视为额外的关键字参数。如果关键字既出现在表达式中,又作为显式关键字参数出现,则会引发TypeError异常。
单个星号*将序列/集合解包到位置参数中,所以你可以这样做:
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
我发现当你想要“存储”一个函数调用时,这特别有用。
例如,假设我有一些单元测试函数'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,除了手动执行add(test[0], test[1])之类的操作,这很难看。此外,如果变量的数量是可变的,那么使用所有您需要的if语句,代码可能会变得非常丑陋。
另一个有用的地方是定义Factory对象(为您创建对象的对象)。 假设你有一个Factory类,它生成Car对象并返回它们。 你可以让myFactory。make_car('red', 'bmw', '335ix')创建Car('red', 'bmw', '335ix'),然后返回它。
def make_car(*args):
return Car(*args)
当您想要调用超类的构造函数时,这也很有用。