【问题标题】:function call with named/unnamed and variable arguments in python在python中使用命名/未命名和可变参数的函数调用
【发布时间】:2012-12-11 14:18:48
【问题描述】:

我有以下代码:

def foo(func, *args, named_arg = None):
    return func(*args)

返回一个SyntaxError:

  File "tester3.py", line 3
    def foo(func, *args, named_arg = None):
                                 ^

这是为什么呢?是否有可能以这种方式定义一个函数,它接受一个参数 (func),然后是一个变量参数列表 args,然后是命名参数?如果没有,我的可能性是什么?

【问题讨论】:

  • 在 Python 3 中工作;这就是您定义不能按位置传递的仅关键字参数的方式。此语法在 Python 2 中不可用。
  • 我在这里的第一个问题与此有关:(stackoverflow.com/questions/9872824/…)

标签: python


【解决方案1】:

包罗万象的*args 参数必须在任何显式参数之后:

def foo(func, named_arg=None, *args):

如果您还将包罗万象的 **kw 关键字参数添加到定义中,那么 必须*args 参数之后:

def foo(func, named_arg=None, *args, **kw):

混合显式关键字参数和包罗万象的*args 参数确实会导致意外行为;您不能同时使用任意位置参数显式命名您同时列出的关键字参数。

func 之外的任何额外位置首先用于named_arg,它也可以作为位置参数:

>>> def foo(func, named_arg = None, *args):
...     print func, named_arg, args
... 
>>> foo(1, 2)
1 2 ()
>>> foo(1, named_arg=2)
1 2 ()
>>> foo(1, 3, named_arg=2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for keyword argument 'named_arg'
>>> foo(1, 2, 3)
1 2 (3,)

这是因为foo() 的任何第二个位置参数将始终用于named_arg

在 Python 3 中,*args 参数可以 放在关键字参数之前,但这具有 的含义。通常,可以在调用签名中将关键字参数指定为位置参数(例如,将您的函数调用为foo(somefunc, 'argument') 会将'argument' 分配给named_arg)。通过在位置参数和命名参数之间放置*args 或普通*,您可以排除命名参数用作位置参数;调用 foo(somefunc, 'argument') 会引发异常。

【讨论】:

  • 当我这样做并定义一个函数如下def func(text): print "Some text: ", text 并通过foo 调用它作为foo(func,'world') 我得到错误TypeError: func() takes exactly 1 argument (0 given)。并且调用foo(func, named_arg = 1, "world") 也不起作用(SyntaxError: non-keyword arg after keyword arg)。
【解决方案2】:

不,Python 2 不允许这种语法。

您的选择是:

1) 将命名的 arg 移动到出现在 *args 之前:

def foo(func, named_arg = None, *args):
   ...

2) 使用**kwargs:

def foo(func, *args, **kwagrs):
   # extract named_arg from kwargs
   ...

3) 升级到 Python 3。

【讨论】:

  • For (2) named_arg = kwargs.get('named_arg', None) 是如何提取具有默认值的命名参数。这可能是对 O.P. 更好的答案,因为解决方案 (1) 会将 foo(f,bar) 与 foo(f,named_arg=bar) 混淆。
【解决方案3】:

将参数的顺序更改为:

def foo(func, named_arg = None, *args):
    return func(*args)

【讨论】:

    【解决方案4】:

    根据文档,没有:

    教程section 4.7.2 说:

    在函数调用中,关键字参数必须跟随位置 论据。

    ...和4.7.3 says 关于“任意参数列表”:

    参数数量可变之前,零个或多个正常 可能会发生争论。

    ...所以如果您要使用所有三种参数类型,它们需要按顺序排列

    1. 位置参数
    2. 命名参数
    3. 可变/任意参数

    【讨论】:

      猜你喜欢
      • 2011-03-09
      • 1970-01-01
      • 2012-11-05
      • 1970-01-01
      • 2016-07-26
      • 2015-07-29
      • 2017-11-25
      • 2015-12-22
      • 1970-01-01
      相关资源
      最近更新 更多