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

时间:2009-07-08 14:45:53

标签: python kwargs

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

kwargs返回一个字典,但设置默认值的最佳方法是什么,或者有一个?我应该只是作为字典访问它吗?使用get函数?

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

一个简单的问题,但我无法找到好的资源。人们在我看过的代码中采用不同的方式,并且很难知道要使用什么。

14 个答案:

答案 0 :(得分:387)

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

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

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

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

答案 1 :(得分:255)

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

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中!

答案 2 :(得分:63)

我建议这样的事情

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,覆盖任何重复的密钥。

答案 3 :(得分:52)

你要做

self.attribute = kwargs.pop('name', default_value)

self.attribute = kwargs.get('name', default_value)

如果您使用pop,则可以检查是否发送了任何虚假值,并采取适当的措施(如果有)。

答案 4 :(得分:39)

使用** kwargs和默认值很容易。但是,有时你不应该首先使用** kwargs。

在这种情况下,我们并没有真正充分利用** kwargs。

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = kwargs.get('val',"default1")
        self.val2 = kwargs.get('val2',"default2")

以上是“为什么要打扰?”宣言。它与

相同
class ExampleClass( object ):
    def __init__(self, val="default1", val2="default2"):
        self.val = val
        self.val2 = val2

当你使用** kwargs时,你的意思是关键字不仅是可选的,而且是有条件的。有比简单默认值更复杂的规则。

当你使用** kwargs时,通常意味着更像下面的内容,其中简单的默认值不适用。

class ExampleClass( object ):
    def __init__(self, **kwargs):
        self.val = "default1"
        self.val2 = "default2"
        if "val" in kwargs:
            self.val = kwargs["val"]
            self.val2 = 2*self.val
        elif "val2" in kwargs:
            self.val2 = kwargs["val2"]
            self.val = self.val2 / 2
        else:
            raise TypeError( "must provide val= or val2= parameter values" )

答案 5 :(得分:26)

由于在参数数量未知时使用**kwargs,为什么不这样做呢?

class Exampleclass(object):
  def __init__(self, **kwargs):
    for k in kwargs.keys():
       if k in [acceptable_keys_list]:
          self.__setattr__(k, kwargs[k])

答案 6 :(得分:13)

这是另一种方法:

def my_func(arg1, arg2, arg3):
    ... so something ...

kwargs = {'arg1': 'Value One', 'arg2': 'Value Two', 'arg3': 'Value Three'}
# Now you can call the function with kwargs like this:

my_func(**kwargs)

答案 7 :(得分:10)

你可以做这样的事情

class ExampleClass:
    def __init__(self, **kwargs):
        arguments = {'val':1, 'val2':2}
        arguments.update(kwargs)
        self.val = arguments['val']
        self.val2 = arguments['val2']

答案 8 :(得分:10)

我认为在Python中使用**kwargs的正确方法是使用字典方法setdefault,如下所示:

class ExampleClass:
    def __init__(self, **kwargs):
        kwargs.setdefault('val', value1)
        kwargs.setdefault('val2', value2)

通过这种方式,如果用户通过&#39; val&#39;或者&#39; val2&#39;在关键字args中,将使用它们;否则,将使用已设置的默认值。

答案 9 :(得分:10)

跟进@srhegde建议使用setattr

class ExampleClass(object):
    __acceptable_keys_list = ['foo', 'bar']

    def __init__(self, **kwargs):
        [self.__setattr__(key, kwargs.get(key)) for key in self.__acceptable_keys_list]

当预期班级包含acceptable列表中的所有项目时,此变体非常有用。

答案 10 :(得分:3)

如果你想将它与* args结合起来,你必须在定义的末尾保留* args和** kwargs。

所以:

def method(foo, bar=None, *args, **kwargs):
    do_something_with(foo, bar)
    some_other_function(*args, **kwargs)

答案 11 :(得分:1)

@AbhinavGupta和@Steef建议使用update(),我发现这对处理大型参数列表非常有用:

args.update(kwargs)

如果我们想检查用户是否未传递任何虚假/不受支持的参数,该怎么办? @VinaySajip指出pop()可用于迭代处理参数列表。然后,任何剩余的争论都是虚假的。好的。

这是另一种可能的方法,它保留了使用update()的简单语法:

# kwargs = dictionary of user-supplied arguments
# args = dictionary containing default arguments

# Check that user hasn't given spurious arguments
unknown_args = user_args.keys() - default_args.keys()
if unknown_args:
    raise TypeError('Unknown arguments: {}'.format(unknown_args))

# Update args to contain user-supplied arguments
args.update(kwargs)

unknown_argsset,其中包含默认值中不存在的参数名称。

答案 12 :(得分:0)

用于处理未知或多个参数的另一个简单解决方案可以是:

class ExampleClass(object):

    def __init__(self, x, y, **kwargs):
      self.x = x
      self.y = y
      self.attributes = kwargs

    def SomeFunction(self):
      if 'something' in self.attributes:
        dosomething()

答案 13 :(得分:0)

** kwargs可以自由添加任意数量的关键字参数。可能会有一个密钥列表,他可以为其设置默认值。但是,不必为无限数量的键设置默认值。最后,将键作为实例属性可能很重要。因此,我将按以下方式进行操作:

class Person(object):
listed_keys = ['name', 'age']

def __init__(self, **kwargs):
    _dict = {}
    # Set default values for listed keys
    for item in self.listed_keys: 
        _dict[item] = 'default'
    # Update the dictionary with all kwargs
    _dict.update(kwargs)

    # Have the keys of kwargs as instance attributes
    self.__dict__.update(_dict)