Proper way to use **kwargs in Python
当涉及到默认值时,Python中使用
1 2 3 4 | class ExampleClass: def __init__(self, **kwargs): self.val = kwargs['val'] self.val2 = kwargs.get('val2') |
这是一个简单的问题,但是我找不到很好的资源。在我所见过的代码中,人们用不同的方式来做这件事,而且很难知道该使用什么。
对于不在字典中的键,可以将默认值传递给
1 | self.val2 = kwargs.get('val2',"default value") |
但是,如果您计划使用具有特定缺省值的特定参数,为什么不首先使用命名参数呢?
1 | def __init__(self, val2="default value", **kwargs): |
虽然大多数答案是这样说的,例如,
1 2 3 4 | def f(**kwargs): foo = kwargs.pop('foo') bar = kwargs.pop('bar') ...etc... |
是"一样的"
1 2 | def f(foo=None, bar=None, **kwargs): ...etc... |
这不是真的。在后一种情况下,
这个习惯用法非常重要,以至于在Python 3中它现在有了特殊的支持语法:
1 2 | def f(*, foo=None, bar=None, **kwargs): ...etc... |
实际上,在python3中,甚至可以有一些关键字参数,它们是不可选的(没有默认值的参数)。
然而,Python 2仍然有很长的生产周期,所以最好不要忘记让您在Python 2中实现重要设计思想的技术和习惯用法,这些设计思想是Python 3语言直接支持的!
我建议这样做
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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'} |
然后可以任意使用这些值
你会做
1 | self.attribute = kwargs.pop('name', default_value) |
或
1 | self.attribute = kwargs.get('name', default_value) |
如果使用
使用**kwargs和默认值很容易。然而,有时您不应该首先使用**kwargs。
在这种情况下,我们并没有充分利用**kwarg。
1 2 3 4 | class ExampleClass( object ): def __init__(self, **kwargs): self.val = kwargs.get('val',"default1") self.val2 = kwargs.get('val2',"default2") |
以上是一个"何苦呢?"的声明。它是一样的
1 2 3 4 | class ExampleClass( object ): def __init__(self, val="default1", val2="default2"): self.val = val self.val2 = val2 |
当您使用**kwargs时,您的意思是一个关键字不仅是可选的,而且是有条件的。有比简单的默认值更复杂的规则。
当您使用**kwargs时,您通常指的是以下内容,其中不应用简单的默认值。
1 2 3 4 5 6 7 8 9 10 11 12 | 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" ) |
既然
1 2 3 4 5 | class Exampleclass(object): def __init__(self, **kwargs): for k in kwargs.keys(): if k in [acceptable_keys_list]: self.__setattr__(k, kwargs[k]) |
这是另一个方法:
1 2 3 4 5 6 7 | 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) |
跟进@srhegde使用setattr的建议:
1 2 3 4 5 | 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] |
当类需要在我们的
我认为在Python中使用默认值
1 2 3 4 | class ExampleClass: def __init__(self, **kwargs): kwargs.setdefault('val', value1) kwargs.setdefault('val2', value2) |
这样,如果用户在关键字
你可以这样做
1 2 3 4 5 6 | class ExampleClass: def __init__(self, **kwargs): arguments = {'val':1, 'val2':2} arguments.update(kwargs) self.val = arguments['val'] self.val2 = arguments['val2'] |
如果您想要将它与*args组合在一起,您必须在定义的末尾保留*args和**kwargs。
所以:
1 2 3 | def method(foo, bar=None, *args, **kwargs): do_something_with(foo, bar) some_other_function(*args, **kwargs) |
@AbhinavGupta和@Steef建议使用
1 | args.update(kwargs) |
如果我们想检查用户是否传递了任何虚假的/不受支持的参数呢?@VinaySajip指出,可以使用
下面是另一种可能的方法,它保持了使用
1 2 3 4 5 6 7 8 9 10 | # 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) |
**kwargs允许添加任意数量的关键字参数。一个人可能有一个键列表,他可以为其设置默认值。但是,为不确定数量的键设置默认值似乎没有必要。最后,将键作为实例属性可能很重要。所以,我将这样做:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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) |
处理未知或多个参数的另一个简单解决方案是:
1 2 3 4 5 6 7 8 9 10 | 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() |