繁体   English   中英

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

[英]Unpacking more than one list as argument for a function

如果我有类似的功能:

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

这就是问题的出处。 而且我知道还有其他方法可以做同样的事情,但只是想了解为什么解压缩一个序列会起作用,但不能解决更多问题。

因为按照函数调用语法 ,这就是定义参数列表的方式

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

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

在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} 

您可以串联列表:

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

代替。

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

不起作用的原因是Python使用实现

一个列表解压缩,并且按照语义,此后的任何参数都必须是命名关键字参数( 或通过 ** 传递命名关键字参数的字典

相比之下,这将起作用。

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

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

Python 2函数签名中只允许使用一个加星标的参数,并且该参数必须在任何位置参数之后并且在任何关键字参数之前。 同样,只允许使用一个双星参数,并且该参数必须跟随签名中的所有关键字参数。 如果您要提交多个参数列表,则确实必须先从它们创建一个列表。

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

*此处不充当运算符。 它更像是函数调用语法的一部分,并且只允许某些有限的可能性。 可以定义语言,以便您可以做自己想做的事情(我已经完成了!),但这不是做出的选择。

这些可能会有所帮助。 请注意,类推就是其他语言中可变数量的参数。 这意味着一旦您说要使用可变数量的参数,所有以下所有参数都属于该列表的一部分(类似于C或C ++对varargs的用法)。

例如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中,星号“ *”用于定义可变数量的参数。 星号字符必须在参数列表中的变量标识符之前。

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

我们从前面的示例中了解到,传递给varpafu()函数调用的参数存储在一个元组中,可以在函数体内将其作为“普通”变量x进行访问。 如果在不带任何参数的情况下调用该函数,则x的值为空元组。

有时,在函数定义中必须使用位置参数,后跟任意数量的参数。 这是可能的,但是位置参数必须始终在任意参数之前。 在下面的示例中,我们有一个位置参数“ 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

如果语法* expression出现在函数调用中,则表达式必须求值为可迭代。 可迭代对象的元素被视为附加的位置参数; 如果存在位置参数x1,...,xN,并且表达式的计算结果为序列y1,...,yM,则等效于使用M + N个位置参数x1,...,xN,y1,...的调用。 ..,yM。

这样的结果是,尽管* expression语法可能会出现在某些关键字参数之后,但会在关键字参数之前(和** expression参数,如果有的话,请参见下文)进行处理。 所以:

>

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

在同一调用中同时使用关键字参数和* expression语法是很不寻常的,因此在实践中不会出现这种混淆。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM