我什么时候在Python中需要函数定义中的*字符?

时间:2016-06-15 14:59:32

标签: python function

我有以下定义的两个函数,

def sumit(func,*args):
    return func(*args)
def sumitt(*args):
    return sum(args)
sumit(sumitt,2,3,4)

我通过将第二行更改为return func(args)进行了一些实验,但我得到了一个错误。但为什么在第4行,它是sum(args)而不是sum(*args)?造成这种不一致的原因是什么?

4 个答案:

答案 0 :(得分:2)

如果您查看文档sum被定义为 -

`sum(iterable[, start])` 

这意味着它正在使用一个可迭代的对象,它将遍历参数本身。

所以

def sumit(func,*args):
    return func(*args)
def sumitt(*args):
    print (args)
    print (*args)
    return sum(args)

出 -

      (1, 2, 3)
      1 2 3

现在你可以看到args是一个元组,而*args解包元素...元组是sum接受的函数接受一个列表的元素,它正在解包。你可以做的是

def sumit(func,*args):
    return func(args)
def sumitt(args):
    print (args)
    print (*args)
    return sum(args)

现在您将整个元组发送到函数sumitt,您可以使用*args解压缩该函数。

1 2 3

这也是以同样的方式工作,但现在你可以看到发生了什么......

答案 1 :(得分:2)

要在每个参数上应用该函数,您需要* 解包函数的参数。

因此func(*args)func(arg1, arg2,...,argn)

是同义的

查看解包

>>> first, second, third = (1, 2, 3)
>>> first
1
>>> second
2
>>> third 
3

但是对于sum,函数的签名要求它需要iterable,因此sum(arg)sum(求和)直接应用于参数元组{ {1}}。

答案 2 :(得分:2)

函数签名中的

*args接受任意参数列表,并使其在函数范围内的args

变量中可用

例如

def my_print(*args):
  """print all arguments passed in"""
  for arg in args:
    try:
      print(arg)
    except:
      print('argument not printable')

d = 'hello'
my_print('a', 1, 'b', d)
# outputs:
a
1
b
hello

在函数调用中将*放在列表或元组前面解压缩列表

my_list = ['a', 1, 'b', d]

my_print(*my_list)
# produces the same output as above.

所以,你定义的第一个函数是:

def sumit(func,*args):
    return func(*args)
  • 接受callable作为第一个位置参数
  • 接受wards上第二个参数的任意参数列表
  • 在名为args
  • 的列表中提供这些参数
  • 返回列表args已解压缩
  • 的可调用对象

在此函数中,第二行不能是return func(args),除非传递的函数接受列表作为第一个位置参数,并且没有其他必需参数

函数sum接受数字的可迭代(列表或元组)并将它们相加。

你可以像这样打电话给sum

my_sum = sum([2, 3, 4])

但是sumitt函数接受参数并在将它们传递给sum函数之前将它们转换为列表

因此,您可以致电sumitt(2, 3, 4),它将返回sum([2, 3, 4])

现在,sumitt进一步包含在sumit中,因此函数调用

sumit(sumitt,2,3,4)

调用sumitt(2, 3, 4),然后调用sum([2, 3, 4])

也可以通过sumit调用sum函数,如下所示:

sumit(sum, [2, 3, 4])

第二个函数sumitt更改sum函数的签名。这在您将动态调用许多不同函数并且您希望其签名相同的情况下非常有用。第一个函数允许您使用任意传递的参数调用任意函数。

例如,如果我定义了这样的平均函数:

def mean(*args):
    return sum(args) / len(args)

然后,均值和总和有不同的签名。

在我的代码中的另一个地方,我不得不调用mean函数或sum函数,我可以这样写:

def sumitt(*args):
    return sum(args)

def apply_func(func, *args):
    return func(*args)

apply_func(sumitt, 2, 3, 4)
# returns 9

apply_func(mean, 2, 3, 4)
# returns 3

答案 3 :(得分:1)

如果你的函数期望单个参数,但是你有一个序列(例如一个列表),你必须指定字符*,以便列表被扩展(解包)到序列中(否则它将是作为一个参数处理)

另一方面,因为函数sum(内置函数python)需要序列(只有一个参数),所以在调用它之前不能展开它。

想象一下,您的args是:

args = [1, 2, 3, 4]

使用func(*args),在评估func时,它将是func(1, 2, 3, 4)

sum(args)将被评估为func([1, 2, 3, 4])