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

607 投票
14 回答
626780 浏览
提问于 2025-04-15 12:46

在Python中,使用**kwargs时,怎样设置默认值才是正确的呢?

kwargs会返回一个字典,但设置默认值的最佳方法是什么呢?或者说有没有最佳方法?我是不是应该直接把它当成字典来用?还是用get函数更好?

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

我看到的代码中,大家的做法各不相同,真不知道该用哪种方式。

14 个回答

105

我建议可以这样做

def testFunc( **kwargs ):
    options = {
            'option1' : 'default_value1',
            'option2' : 'default_value2',
            'option3' : 'default_value3', }

    options.update(kwargs)
    print options

testFunc( option1='new_value1', option3='new_value3' )
# {'option2': 'default_value2', 'option3': 'new_value3', 'option1': 'new_value1'}

testFunc( option2='new_value2' )
# {'option1': 'default_value1', 'option3': 'default_value3', 'option2': 'new_value2'}

然后你可以随意使用这些值

dictionaryA.update(dictionaryB) 这个操作是把 dictionaryB 的内容添加到 dictionaryA 中,如果有重复的键,就会覆盖掉原来的值。

308

虽然大多数回答都说,比如说:

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 中得到了直接支持!

641

你可以给get()方法传一个默认值,这样如果字典里没有你要找的键,就会返回这个默认值:

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

不过,如果你打算用某个特定的参数和特定的默认值,那为什么不直接使用命名参数呢?

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

撰写回答