args / kwargs的特殊用法

3
我需要做类似于以下的事情:
def func1(a, *args, b="BBB", **kwargs):
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, kwargs)

这样调用:

func1("AAAA", h="HHH", j="JJJ")

生成输出:
a=AAAA b=BBB args=() kwargs={'h': 'HHH', 'j': 'JJJ'}

但是不可能在*args之后放置一个默认的命名参数。(SyntaxError: invalid syntax

  • 为什么不允许这样做?
  • 有没有一种可读性更好的实现方式?我唯一知道的方法是b=kwargs.pop("b", "BBB"),但这并不是非常易读。我更喜欢将其放在函数调用定义中,因为它是一个参数,它将始终具有一个值,无论是默认值还是用户给定的值。

编辑

我可以将b放在args之前:

def func1(a, b="BBB", *args, **kwargs):
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, kwargs)

但这意味着这个调用:
func1("AAAA", "CCC", h="HHH", j="JJJ")

"CCC" 分配给 b,但我不想要这个。我希望 b 成为一个命名参数,而不是一个位置参数。

3
为什么不在 *args 之前加上 b='BBB' ? - djc
3个回答

2

1

在Python 2中,

当前的Python函数调用范例允许参数通过位置或关键字指定。参数可以通过名称显式填写,也可以通过位置隐式填写。

因此,def func1(a, *args, b="BBB", **kwargs)是有歧义的,因此不被允许:在调用func1(1, 2)时,args == ()b == 2,还是args = (2,)b == "BBB"

这就是为什么def func1(a, b="BBB", *args, **kwargs)被接受(尽管它不做你想要的):无论如何b总是作为第二个参数传递,即使在像func1(1, c=3, b=2)这样的调用中(它相当于func1(1, 2, c=3))。

作为ecatmur所指出的,Python 3改变了参数处理方式,这带来了您所需要的灵活性。

0
def func1(a, *args, **kwargs):
    b, k = (lambda b="BBBB", **k: b, k)(**kwargs)
    print "a=%s b=%s args=%s kwargs=%s" % (a, b, args, k)

可能是一种替代方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接