【问题标题】:why doesn't ** unpack kwargs in function calls?为什么 ** 在函数调用中不解包 kwargs?
【发布时间】:2012-05-29 20:47:28
【问题描述】:

这是困扰我一段时间的事情:

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

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

我假设底部的 aFunc 调用中的 target='test' 最终会出现在 kwargs 中(确实如此),并且我还假设 ** 会在函数调用中解包 kwargs,因此 target 将作为aFunc 中的关键字参数。它没有。我知道它是以字典的形式出现的,但我需要在参数列表中解压该字典。这可能吗?简而言之,有没有办法让 *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 次。

这当然会失败,因为 wrapper 无法处理 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,它们实际上都会填写参数,而不是列表和字典。包装器中的文档将解释要求。如果您传入 inputList,它实际上会进入,并且从包装器回调 repeatList 的 inputList 将是有效的。如果您没有传入 inputList,它会在对 repeatList 的回调中使用默认列表创建它。如果您的函数不在乎,但使用了 *kwargs,它会优雅地接受它而不会出现问题。

如果以上任何一个错误(超出一般概念),我们深表歉意。我在这里打出来的,未经测试,已经很晚了。

【问题讨论】:

  • "我需要在参数列表中解压该字典。" – 我无法想象你需要这个的任何理由。可以请教一下吗?
  • 如果您知道要获得哪些选项,那为什么还要使用**kwargs
  • 如何更好地去做?你不知道我在做什么。我只是问我是否可以在参数中解压缩列表和字典。它没有抱怨。它只是在陈述一个事实。这个网站有一个非常困难的人群。我问直截了当的问题——有可能做到这一点吗?有一个代码示例 - 我总是遇到有人问“你到底为什么要这样做?”也许我没有。我只是想知道我是否可以。
  • @GaryFixler:你试图在这个问题中实现的目标毫无意义,所以人们指出这一点是很自然的。
  • @jamylak - 你给人的印象是非常辱骂。我已经在 Python 中工作了 3 年。我整天都在用 Python 解决问题,但有时我想不通,就像这个简单的事情 - 我被告知 **dict 将 dict 解压缩为 key=value 对,但实际上似乎并没有以这种方式工作,我一直无法弄清楚更多关于它的信息。稀有、奇怪的东西——我可能永远不会使用的东西——是我在这里问的东西,因为我可以自己或通过谷歌解决其他所有问题。我不是要冒犯人。我试图了解什么是可能的。

标签: python arguments keyword-argument


【解决方案1】:

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

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

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

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

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

但是,如果您想要破解(仅限教育用途)来解压 **kwargs,您可以尝试:

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

【讨论】:

  • 感谢您回答问题。看来这是不可能的。
  • 有可能,这只是一个坏主意,就像 99% 的时间有人认为他们想要动态创建变量名。
  • 很好的答案,但是“*args 无法自动解包,因为没有关联的变量名”是什么意思。
  • 感谢您的更新,数学。我绝对不想这样做:)
  • target = kwargs.get('target', '&lt;default-value&gt;') 位非常适合在您希望在 url 中包含可选关键字变量的 Bottle/Flask 类型的应用程序中使用
【解决方案2】:

这种特殊情况的明显方法是

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

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

如果您想通过名称访问函数内部的参数,请在参数列表中明确命名。

【讨论】:

  • 这没有回答问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-01
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 1970-01-01
  • 2016-12-03
相关资源
最近更新 更多