在函数调用中,星号运算符是什么意思?

问题:在函数调用中,星号运算符是什么意思?

*运算符在Python中是什么意思,例如likezip(*x)或代码f(**k)

  1. 在解释器内部如何处理?
  2. 它会影响性能吗?是快还是慢?
  3. 什么时候有用,什么时候没有?
  4. 应该在函数声明中还是在调用中使用它?

What does the * operator mean in Python, such as in code like zip(*x) or f(**k)?

  1. How is it handled internally in the interpreter?
  2. Does it affect performance at all? Is it fast or slow?
  3. When is it useful and when is it not?
  4. Should it be used in a function declaration or in a call?

回答 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

The single star * unpacks the sequence/collection into positional arguments, so you can do this:

def sum(a, b):
    return a + b

values = (1, 2)

s = sum(*values)

This will unpack the tuple so that it actually executes as:

s = sum(1, 2)

The double star ** does the same, only using a dictionary and thus named arguments:

values = { 'a': 1, 'b': 2 }
s = sum(**values)

You can also combine:

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)

will execute as:

s = sum(1, 2, c=10, d=15)

Also see section 4.7.4 – Unpacking Argument Lists of the Python documentation.


Additionally you can define functions to take *x and **y arguments, this allows a function to accept any number of positional and/or named arguments that aren’t specifically named in the declaration.

Example:

def sum(*values):
    s = 0
    for v in values:
        s = s + v
    return s

s = sum(1, 2, 3, 4, 5)

or with **:

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # returns 1

this can allow you to specify a large number of optional parameters without having to declare them.

And again, you can combine:

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。这里的*和**是函数声明和调用语法的一部分。

One small point: these are not operators. Operators are used in expressions to create new values from existing values (1+2 becomes 3, for example. The * and ** here are part of the syntax of function declarations and calls.


回答 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)

当您要调用超类的构造函数时,这也很有用。

I find this particularly useful for when you want to ‘store’ a function call.

For example, suppose I have some unit tests for a function ‘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

There is no other way to call add, other than manually doing something like add(test[0], test[1]), which is ugly. Also, if there are a variable number of variables, the code could get pretty ugly with all the if-statements you would need.

Another place this is useful is for defining Factory objects (objects that create objects for you). Suppose you have some class Factory, that makes Car objects and returns them. You could make it so that myFactory.make_car(‘red’, ‘bmw’, ‘335ix’) creates Car(‘red’, ‘bmw’, ‘335ix’), then returns it.

def make_car(*args):
   return Car(*args)

This is also useful when you want to call a superclass’ constructor.


回答 3

它称为扩展调用语法。从文档中

如果语法* expression出现在函数调用中,则表达式必须计算为序列。来自此序列的元素被视为它们是附加的位置参数。如果存在位置参数x1,…,xN,并且表达式的计算结果为序列y1,…,yM,则等效于使用M + N个位置参数x1,…,xN,y1,…的调用。 ..,yM。

和:

如果语法** expression出现在函数调用中,则expression必须计算为一个映射,该映射的内容被视为其他关键字参数。如果关键字同时出现在表达式中并作为显式关键字参数出现,则会引发TypeError异常。

It is called the extended call syntax. From the documentation:

If the syntax *expression appears in the function call, expression must evaluate to a sequence. Elements from this sequence are treated as if they were additional positional arguments; if there are positional arguments x1,…, xN, and expression evaluates to a sequence y1, …, yM, this is equivalent to a call with M+N positional arguments x1, …, xN, y1, …, yM.

and:

If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments. In the case of a keyword appearing in both expression and as an explicit keyword argument, a TypeError exception is raised.


回答 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})”。

In a function call the single star turns a list into seperate arguments (e.g. zip(*x) is the same as zip(x1,x2,x3) if x=[x1,x2,x3]) and the double star turns a dictionary into seperate keyword arguments (e.g. f(**k) is the same as f(x=my_x, y=my_y) if 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})”.