在 Python 中使用 \*\*kwargs 的正确方法

新手上路,请多包涵

当涉及到默认值时,在 Python 中使用 **kwargs 的正确方法是什么?

kwargs 返回字典,但是设置默认值的最佳方法是什么,或者有没有?我应该把它作为字典访问吗?使用获取功能?

 class ExampleClass:
    def __init__(self, **kwargs):
        self.val = kwargs['val']
        self.val2 = kwargs.get('val2')

一个简单的问题,但我找不到好的资源。人们在我见过的代码中以不同的方式做到这一点,很难知道该使用什么。

原文由 Kekoa 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 396
2 个回答

您可以将默认值传递给 get() 对于不在字典中的键:

 self.val2 = kwargs.get('val2',"default value")

但是,如果您计划使用具有特定默认值的特定参数,为什么不首先使用命名参数呢?

 def __init__(self, val2="default value", **kwargs):

原文由 balpha 发布,翻译遵循 CC BY-SA 2.5 许可协议

虽然大多数答案都是这样说的,例如,

 def f(**kwargs):
    foo = kwargs.pop('foo')
    bar = kwargs.pop('bar')
    ...etc...

是相同的”

 def f(foo=None, bar=None, **kwargs):
    ...etc...

这不是真的。在后一种情况下, f 可以称为 f(23, 42) ,而前一种情况 接受命名参数 - 没有位置调用。通常您希望允许调用者具有最大的灵活性,因此,正如大多数答案所断言的那样,第二种形式更可取:但情况并非总是如此。当您接受许多通常只有少数被传递的可选参数时,强制使用命名参数 -- threading.Thread 可能是一个好主意(避免在调用站点发生意外和不可读的代码!)一个例子。第一种形式是如何在 Python 2 中实现它。

这个习惯用法非常重要,以至于在 Python 3 中它现在有特殊的支持语法:在 def 签名中的单个 * 之后的每个参数都是关键字,也就是说,不能传递为位置参数,但仅作为命名参数。所以在 Python 3 中,你可以将上面的代码编码为:

 def f(*, foo=None, bar=None, **kwargs):
    ...etc...

实际上,在 Python 3 中,您甚至可以拥有 可选的仅限关键字的参数(没有默认值的参数)。

然而,Python 2 仍然有很长的生产寿命,所以最好 不要 忘记让您在 Python 2 中实现重要设计思想的技术和习惯用法,这些思想在 Python 3 语言中直接支持!

原文由 Alex Martelli 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题