*运算符在Python中是什么意思,例如在zip(*x)或f(**k)之类的代码中?
*
zip(*x)
f(**k)
在函数调用中,单星将列表转换为单独的参数(例如zip(*x)与zip(x1,x2,x3)相同ifx=[x1,x2,x3]),双星将字典转换为单独的关键字参数(例如f(**k)与f(x=my_x, y=my_y)相同ifk = {'x':my_x, 'y':my_y}。
zip(x1,x2,x3)
x=[x1,x2,x3]
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 foo(*x)
foo(1,2,3)
x
[1,2,3]
def bar(**k)
bar(x=42, y=23)
k
{'x': 42, 'y': 23}
它被称为扩展调用语法。从留档:
如果语法*表达式出现在函数调用中,则表达式必须计算为序列。此序列中的元素将被视为附加位置参数;如果有位置参数x1,…, xN,并且表达式计算为序列y1,…, yM,这等效于具有M+N个位置参数x1,…, xN, y1,…, yM的调用。
和:
如果语法**表达式出现在函数调用中,则表达式必须计算为映射,其内容将被视为附加关键字参数。如果关键字同时出现在表达式和显式关键字参数中,则会引发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参数,这允许函数接受任意数量的位置和/或命名参数,这些参数在声明中没有具体命名。
*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(test[0], test[1])的操作之外,没有其他方法可以调用add,这很难看。此外,如果有可变数量的变量,则代码可能会因为您需要的所有if语句而变得非常难看。
add(test[0], test[1])
另一个有用的地方是定义工厂对象(为您创建对象的对象)。 假设您有一个类Factory,它创建Car对象并返回它们。 你可以让myFactory.make_car('red', 'bmw', '335ix')创建Car('red', 'bmw', '335ix'),然后返回它。
myFactory.make_car('red', 'bmw', '335ix')
Car('red', 'bmw', '335ix')
def make_car(*args): return Car(*args)
当您想调用超类的构造函数时,这也很有用。