为什么不在函数调用中解压缩kwargs?

时间:2012-05-23 10:02:46

标签: python arguments kwargs

这件事现在让我误解了一段时间:

def test (*args, **kwargs):
    print target

test(foo='bar', target='baz')

我认为底部的aFunc调用中的target='test'最终会出现在kwargs中(并且确实如此),我还假设**会在函数调用中解包kwargs,因此目标将存在作为aFunc中的关键字参数。它没有。我知道它作为一个dict出现,但我需要在参数列表中解压缩该dict。这可能吗?简而言之,有没有办法让* args和** kwargs消失并让实际的args和kwargs进入通话?

编辑:我把一个案例解释为* args和** kwargs的解包可能会有所帮助:

假设我有一个打印列表的函数:

def printList (inputList=None):
    print inputList

我希望能够不传递任何列表并提供默认列表:

def ensureList (listFunc):
    def wrapper (inputList=None):
        listFunc(inputList=inputList or ['a','default','list'])
    return wrapper

@ensureList
def printList (inputList=None):
    print inputList

现在我希望列表转发器更加复杂:

@ensureList
def repeatList (inputList=None):
    print inputList*2

工作正常。但现在我想要变量重复:

@ensureList
def repeatList (times, inputList=None):
    print inputList*times

现在你可以说:

repeatList(5)

它将生成默认列表并重复5次。

这当然失败了,因为包装器无法处理times参数。我当然可以这样做:

@ensureList
def repeatList (inputList=None, times=1)

但是我总是要这样做:

repeatList(times=5)

也许在某些情况下我想强制提供一个值,所以非关键词arg是有道理的。

当我去年第一次遇到这样的问题时,我认为一个简单的解决方案是删除包装器上的要求:

def ensureList (listFunc):
    "info here re: operating on/requiring an inputList keyword arg"
    def wrapper (*args, **kwargs):
        listFunc(inputList=inputList or ['a','default','list'])
    return wrapper
但是,这不起作用。这就是为什么我想让args和kwargs实际扩展,或者我想有办法进行扩展。然后无论我提供什么args和kwargs,他们实际上都填写了参数,而不是列表和dict。包装器中的文档将解释需求。如果你传入inputList,它实际上会进入,并且回调到包装器中的repeatList的inputList是有效的。如果你没有传入inputList,它将在使用默认列表的repeatList的回调中创建它。如果你的功能不关心,但是使用* kwargs,它会毫无问题地优雅地接受它。

如果上述任何一个错误(超出一般概念),请道歉。我在这里输入了它,未经测试,现在已经很晚了。

2 个答案:

答案 0 :(得分:14)

为什么不在函数调用中解压缩kwargs?”的答案是:因为这是一个坏主意,开发函数的人不希望局部变量只是依赖于在呼叫参数上。

所以,这不是它的工作方式,你肯定不希望python表现得那样。

要访问函数中的target变量,您可以使用:

def test(target='<default-value>', *args, **kwargs):
    print target

def test(*args, **kwargs):
    target = kwargs.get('target', '<default-value>')
    print target

但是,如果你想要一个hack(仅限教育用途)解包** kwargs,你可以尝试:

def test(*args, **kwargs):
    for i in kwargs:
        exec('%s = %s' % (i, repr(kwargs[i])))
    print target

答案 1 :(得分:2)

这种特殊情况的显而易见的方法是

def test(foo=None, target=None):
    print target

test(foo='bar', target='baz')

如果要按名称访问函数内的参数,请在参数列表中明确命名。