首页 文章

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

提问于
浏览
358

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

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

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

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

13 回答

  • 10

    你可以这样做

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

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

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

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

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

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

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

    是相同的”

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

    这不是真的 . 在后一种情况下, f 可以被称为 f(23, 42) ,而前一种情况接受命名参数 only - 没有位置调用 . 通常,您希望允许调用者具有最大的灵活性,因此第二种形式(因为大多数答案断言)更可取:但情况并非总是如此 . 当你接受许多可选参数时,通常只有少数几个被传递,这可能是一个很好的想法(避免在你的呼叫站点发生意外和不可读的代码!)来强制使用命名参数 - 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语言直接支持的重要设计思想的技巧和习惯用法!

  • 362

    我建议这样的事情

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

  • 50

    你做的

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

    要么

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

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

  • 12

    使用** 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" )
    
  • 24

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

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

    这是另一种方法:

    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)
    
  • 61

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

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

    这样,如果用户在关键字 args 中传递'val'或'val2',则会使用它们;否则,将使用已设置的默认值 .

  • 1

    关注@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

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

    所以:

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

    @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 ,其中包含默认值中不存在的参数名称 .

  • 241

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

    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()
    

相关问题