解压缩多个列表作为函数的参数

时间:2014-02-28 14:37:55

标签: python

如果我有以下功能:

def f(a,b,c,d):
    print a,b,c,d

那么为什么会这样:

f(1,2,3,4)
f(*[1,2,3,4])

但不是这样:

f(*[1,2] , *[3,4])
    f(*[1,2] , *[3,4])
               ^
SyntaxError: invalid syntax

编辑: 有关信息,最初的问题是替换函数包装器中的一个参数。我想替换输入的* args的给定成员并尝试类似:

def vectorize_pos(f,n=0):
    '''
    Decorator, vectorize the processing of the nth argument
    :param f: function that dont accept a list as nth argument
    '''
    def vectorizedFunction(*args,**kwargs):
        if isinstance(args[n],list):
            return map(lambda x : f( *(args[:n]) , x , *(args[n+1,:]), **kwargs),args[n])
        else:
            return f(*args,**kwargs)
    return vectorizedFunction

问题出现在那里。而且我知道还有其他方法可以做同样的事情,但只是想了解为什么解压缩一个序列有效但不是更多。

7 个答案:

答案 0 :(得分:19)

因为,根据Function call syntax,这是参数列表的定义方式

argument_list ::=  positional_arguments ["," keyword_arguments]
                     ["," "*" expression] ["," keyword_arguments]
                     ["," "**" expression]
                   | keyword_arguments ["," "*" expression]
                     ["," keyword_arguments] ["," "**" expression]
                   | "*" expression ["," keyword_arguments] ["," "**" expression]
                   | "**" expression

因此,每个函数调用只能传递一个* expression

答案 1 :(得分:13)

从Python 3.5开始, 工作

PEP 448在Python 3.5中实现。引用PEP,它允许,除其他外:

  

任意定位解包运营商:

>>> print(*[1], *[2], 3)
1 2 3
>>> dict(**{'x': 1}, y=2, **{'z': 3})
{'x': 1, 'y': 2, 'z': 3}

答案 2 :(得分:5)

您可以连接列表:

>>> f(*[1,2]+[3,4])
1 2 3 4

或使用itertools.chain

>>> from itertools import chain
>>> f(*chain([1,2], [3,4]))
1 2 3 4

答案 3 :(得分:5)

工作。

>>>def f(a,b,c,d):
         print('hello') #or whatever you wanna do. 
>>>f(1,2,*[3,4])
hello

不起作用的原因是Python使用this

实现了这一点

一个列表解包,并且遵循语义,之后的任何参数必须是命名关键字参数(或通过 **传递命名关键字参数的dictonary)

通过对比,这可行。

>>>def f(a,b,c,k):
       pass
>>>f(1,*[2,3],k=4)

答案 4 :(得分:4)

它没有用,因为它的语法无效 - 也就是说,它实际上并不是Python,尽管它看起来像。

Python 2函数签名中只允许使用一个已加星标的参数,它必须遵循任何位置参数并在任何关键字参数之前。类似地,只允许一个双星参数,它必须遵循签名中的所有关键字参数。如果您想要提交多个参数列表,则必须首先从它们创建一个列表。

在Python 3中,也可以单独使用星号来表示任何以下参数都是所谓的仅关键字参数,但我认为我们还不需要进入。

答案 5 :(得分:3)

这里的*不是作为运营商。它更像是函数调用语法的一部分,它只允许某些有限的可能性。可以定义语言,以便你可以做你想做的事情(我已经完成了!),但这不是你做出的选择。

答案 6 :(得分:3)

这些可能有所帮助。请注意,类比是其他语言中可变数量的参数。这意味着一旦你说你要使用可变数量的参数,所有后面的参数都是该列表的一部分(类似于使用varargs的C或C ++)。

例如,

    f = [1,2,3,4,5]

def func(a, b, c, d)
  print a, b, c, d

func(f) # Error 1 argument, 4 required

func(*f) # Error 5 arguments 4 required

http://www.python-course.eu/passing_arguments.php

  

可变长度参数
  我们现在将介绍其中的功能   可以采用任意数量的参数。那些有一些   用C或C ++编程背景从varargs特性中知道这一点   这些语言。 Python中使用星号“*”来定义   可变数量的参数。星号字符必须在a之前   参数列表中的变量标识符。

>>> def varpafu(*x): print(x)
... 
>>> varpafu()
()
>>> varpafu(34,"Do you like Python?", "Of course")
(34, 'Do you like Python?', 'Of course')
>>> 
     

我们从前面的例子中学习,传递给的参数   varpafu()的函数调用是在元组中收集的,可以是元组   作为函数体内的“正常”变量x访问。如果   在没有任何参数的情况下调用该函数,x的值为a   空元组。

     

有时候,有必要使用位置参数后跟一个   函数定义中的任意数量的参数。这是   可能,但位置参数总是必须先于   任意参数。在下面的例子中,我们有一个位置   参数“city”, - 主要位置, - 总是必须的   给定,然后是任意数量的其他位置:

>>> def locations(city, *other_cities): print(city, other_cities)
... 
>>> locations("Paris")
('Paris', ())
>>> locations("Paris", "Strasbourg", "Lyon", "Dijon", "Bordeaux", "Marseille")
('Paris', ('Strasbourg', 'Lyon', 'Dijon', 'Bordeaux', 'Marseille'))
>>>

http://docs.python.org/2.7/reference/expressions.html

  

如果语法*表达式出现在函数调用表达式中   必须评估为可迭代。处理此可迭代的元素   好像他们是额外的位置论点;如果有   位置参数x1,...,xN和表达式求值为a   序列y1,...,yM,这相当于具有M + N位置的调用   参数x1,...,xN,y1,...,yM。

     

这样做的结果是虽然*表达式语法可能   在一些关键字参数之后出现,它在之前被处理   关键字参数(和**表达式参数,如果有的话 - 见下文)。   所以:

     
    
      

>

    
  
>>> def f(a, b): ...  print a, b ...
>>> f(b=1, *(2,)) 2 1
>>> f(a=1, *(2,)) Traceback (most recent call last):   File "<stdin>", line 1, in ? TypeError: f() got multiple values for keyword argument
'a'
>>> f(1, *(2,)) 1 2
     

关键字参数和*表达式语法都不常见   在同一个电话中使用,所以在实践中这种混淆不会   出现。

     

如果语法**表达式出现在函数调用表达式中   必须评估映射,其内容被视为   其他关键字参数。如果出现关键字   表达式和显式关键字参数都是TypeError   异常被提出。