星级算子是什么意思?

psi*_*lia 559 python syntax parameter-passing argument-unpacking iterable-unpacking

*运算符在Python 中的含义是什么,例如在代码中zip(*x)f(**k)

  1. 如何在解释器内部处理?
  2. 它会影响性能吗?是快还是慢?
  3. 什么时候有用,什么时候不用?
  4. 它应该用于功能声明还是通话中?

ang*_*son 861

单个星形*将序列/集合解压缩为位置参数,因此您可以这样做:

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

values = (1, 2)

s = sum(*values)
Run Code Online (Sandbox Code Playgroud)

这将解压缩元组,使其实际执行如下:

s = sum(1, 2)
Run Code Online (Sandbox Code Playgroud)

双星**做同样的事情,只使用字典并因此命名参数:

values = { 'a': 1, 'b': 2 }
s = sum(**values)
Run Code Online (Sandbox Code Playgroud)

你也可以结合:

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

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)
Run Code Online (Sandbox Code Playgroud)

将执行为:

s = sum(1, 2, c=10, d=15)
Run Code Online (Sandbox Code Playgroud)

另请参见4.7.4 - 解压缩 Python文档的参数列表.


此外,您可以定义要采用的函数*x**y参数,这允许函数接受在声明中未明确命名的任意数量的位置和/或命名参数.

例:

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

s = sum(1, 2, 3, 4, 5)
Run Code Online (Sandbox Code Playgroud)

或者**:

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

s = get_a(a=1, b=2)      # returns 1
Run Code Online (Sandbox Code Playgroud)

这可以让您指定大量可选参数而无需声明它们.

再次,你可以结合:

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
Run Code Online (Sandbox Code Playgroud)

  • 当然,但是你必须要调用它:`s = sum((1,2,3,4,5))`或`s = sum([1,2,3,4,5])`, `*values`选项使调用看起来像需要许多参数,但它们被打包成函数代码的集合. (26认同)
  • 这是真正的好处:如果需要可变数量的参数,您可以编写本来不可能的函数.例如,C的printf函数(具有1 + n个参数)对于任何初级程序员来说都很难写.在Python中,初学者可以编写def printf(string_template,*args)并继续前进. (9认同)
  • 为什么你需要这个,如果没有扩展它的功能就不能迭代提供的列表? (4认同)
  • 如果您(可能是偶然地 :p)将字典打开时只有一个 * 而不是两个,会发生什么?好像做了什么,好像是一个元组出来了,但又不是那么明显是什么。(编辑:好的,我认为答案是它只是解压密钥,丢弃值) (2认同)
  • 最后一个例子意味着 * 和 ** 不仅进行解包,还进行打包!请参阅这个优秀的页面 https://www.codingame.com/playgrounds/500/advanced-python-features#unpacking (2认同)

Ned*_*der 40

一点是:这些不是运营商.运算符在表达式中用于从现有值创建新值(例如,1 + 2变为3.*和**这里是函数声明和调用语法的一部分.

  • 请注意,Python文档在此上下文中调用*作为运算符; 我同意,这有点误导. (5认同)

Don*_*ner 17

我发现这对于你想要"存储"一个函数调用特别有用.

例如,假设我对函数'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
Run Code Online (Sandbox Code Playgroud)

没有其他方法可以调用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)
Run Code Online (Sandbox Code Playgroud)

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

  • 我故意在那里放一些会失败的东西:) (5认同)
  • 我喜欢你的例子.但是,我认为-1 + 3 == 2. (3认同)

Mar*_*ers 16

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

如果语法*表达式出现在函数调用中,则表达式必须求值为序列.来自这个序列的元素被视为它们是额外的位置参数; 如果存在位置参数x1,...,xN,并且表达式求值为序列y1,...,yM,则这相当于具有M + N个位置参数x1,...,xN,y1,...的调用. ..,是的.

和:

如果语法**表达式出现在函数调用中,则表达式必须求值为映射,其内容被视为附加关键字参数.如果关键字出现在表达式和显式关键字参数中,则会引发TypeError异常.

  • 只需在教科书答案中添加一个脚注 - 在语法支持到达之前,使用内置的`apply()`函数实现了相同的功能 (3认同)

sep*_*p2k 14

在函数调用中,单个星形将列表转换为单独的参数(例如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})".

  • 一个(非常)迟到的评论,但我相信从`def foo(*x)` *x 给出了一个元组,而不是一个列表。 (3认同)

归档时间:

查看次数:

167854 次

最近记录:

6 年 前