关于python:star操作符是什么意思?

What does the star operator mean?

本问题已经有最佳答案,请猛点这里访问。

在python中,*操作符是什么意思,比如在zip(*x)f(**k)之类的代码中?

  • 在口译员内部如何处理?
  • 它会影响性能吗?是快还是慢?
  • 什么时候有用,什么时候不有用?
  • 它应该在函数声明中使用还是在调用中使用?

  • 单星*将序列/集合解包为位置参数,因此可以这样做:

    1
    2
    3
    4
    5
    6
    def sum(a, b):
        return a + b

    values = (1, 2)

    s = sum(*values)

    这将解包元组,使其实际执行为:

    1
    s = sum(1, 2)

    双星**也一样,只使用字典和命名的参数:

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

    您还可以组合:

    1
    2
    3
    4
    5
    6
    def sum(a, b, c, d):
        return a + b + c + d

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

    执行方式:

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

    另请参见第4.7.4节-打开python文档的参数列表。

    此外,还可以定义接受*x**y参数的函数,这允许函数接受声明中没有特别指定的任何数量的位置和/或命名参数。

    例子:

    1
    2
    3
    4
    5
    6
    7
    def sum(*values):
        s = 0
        for v in values:
            s = s + v
        return s

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

    或与**一起:

    1
    2
    3
    4
    def get_a(**values):
        return values['a']

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

    这允许您指定大量可选参数,而不必声明它们。

    同样,您可以组合:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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)创建新值。这里的*和**是函数声明和调用语法的一部分。


    我发现当你想"存储"一个函数调用时,这个特别有用。

    例如,假设我对函数"add"进行了一些单元测试:

    1
    2
    3
    4
    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

    除了手动执行诸如"添加"(测试[0],测试[1])之类的难看的操作之外,没有其他方法可以调用"添加"。此外,如果变量的数量是可变的,那么代码可能会变得非常难看,因为您需要所有的if语句。

    另一个有用的地方是定义工厂对象(为您创建对象的对象)。假设您有一个类工厂,它生成汽车对象并返回它们。你可以这样做,使我的工厂。使汽车(‘红色’、‘宝马’、‘335ix’)创建汽车(‘红色’、‘宝马’、‘335ix’),然后返回它。

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

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


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

    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.

    还有:

    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.


    在函数调用中,如果x=[x1,x2,x3]的话,单星将列表转换成单独的参数(例如zip(*x)zip(x1,x2,x3)相同;如果x=[x1,x2,x3]的话,双星将字典转换成单独的关键字参数(例如f(**k)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}