在Python中使用**kwargs的正确方法
当涉及到默认值时,在Python中使用在Python中使用**kwargs的正确方法,python,keyword-argument,Python,Keyword Argument,当涉及到默认值时,在Python中使用**kwargs的正确方法是什么 kwargs返回一个字典,但是设置默认值的最佳方法是什么,或者有没有?我是不是应该把它当作字典来查?使用get函数 class ExampleClass: def __init__(self, **kwargs): self.val = kwargs['val'] self.val2 = kwargs.get('val2') 一个简单的问题,但我找不到好的资源。人们用我见过的代码做这
**kwargs
的正确方法是什么
kwargs
返回一个字典,但是设置默认值的最佳方法是什么,或者有没有?我是不是应该把它当作字典来查?使用get函数
class ExampleClass:
def __init__(self, **kwargs):
self.val = kwargs['val']
self.val2 = kwargs.get('val2')
一个简单的问题,但我找不到好的资源。人们用我见过的代码做这件事的方式不同,很难知道该用什么。对于字典中没有的键,可以将默认值传递给
get()
:
self.val2 = kwargs.get('val2',"default value")
但是,如果计划使用具有特定默认值的特定参数,为什么不首先使用命名参数
def __init__(self, val2="default value", **kwargs):
你会的
self.attribute = kwargs.pop('name', default_value)
或
如果使用
pop
,则可以检查是否发送了任何虚假值,并采取适当的措施(如果有)。您可以这样做
class ExampleClass:
def __init__(self, **kwargs):
arguments = {'val':1, 'val2':2}
arguments.update(kwargs)
self.val = arguments['val']
self.val2 = arguments['val2']
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'}
使用**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
def f(foo=None, bar=None, **kwargs):
...etc...
当您使用**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" )
我建议这样做
class ExampleClass:
def __init__(self, **kwargs):
arguments = {'val':1, 'val2':2}
arguments.update(kwargs)
self.val = arguments['val']
self.val2 = arguments['val2']
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
中,覆盖任何重复的键。而大多数答案都是这样说的,例如
def f(**kwargs):
foo = kwargs.pop('foo')
bar = kwargs.pop('bar')
...etc...
“与”相同吗
事实并非如此。在后一种情况下,f
可以被称为f(23,42)
,而前一种情况只接受命名参数,不接受位置调用。通常,您希望允许调用者具有最大的灵活性,因此,正如大多数答案所断言的那样,第二种形式更可取:但情况并非总是如此。当您接受许多可选参数(通常只传递其中的少数参数)时,强制使用命名参数可能是一个很好的主意(避免在调用站点出现意外和无法读取的代码!)线程化就是一个例子。第一种形式是如何在Python2中实现它
这个习惯用法非常重要,因此在Python3中,它现在有了特殊的支持语法:def
签名中单个*
后面的每个参数都是仅关键字,也就是说,不能作为位置参数传递,而只能作为命名参数传递。因此,在Python 3中,您可以将上述内容编码为:
def f(*, foo=None, bar=None, **kwargs):
...etc...
事实上,在Python3中,甚至可以有非可选的仅关键字参数(没有默认值的参数)
然而,Python2还有很长的生产寿命,因此最好不要忘记让您在Python2中实现Python3语言直接支持的重要设计思想的技术和习惯用法 还有另一种方法:
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)
如果要将其与*args组合,则必须在定义末尾保留*args和**kwargs 因此:
既然
**kwargs
是在参数数量未知时使用的,为什么不这样做呢
class Exampleclass(object):
def __init__(self, **kwargs):
for k in kwargs.keys():
if k in [acceptable_keys_list]:
self.__setattr__(k, kwargs[k])
我认为在Python中使用默认值的正确方法是使用dictionary方法
setdefault
,如下所示:
class ExampleClass:
def __init__(self, **kwargs):
kwargs.setdefault('val', value1)
kwargs.setdefault('val2', value2)
这样,如果用户在关键字args
中传递“val”或“val2”,则将使用它们;否则,将使用已设置的默认值。跟进使用建议:
当类希望在我们的
可接受的列表中包含所有项时,此变量非常有用。@AbhinavGupta和@Steef建议使用update()
,我发现这对处理大型参数列表非常有帮助:
args.update(kwargs)
如果我们想检查用户没有传递任何虚假/不受支持的参数,该怎么办@VinaySajip指出,pop()
可以用于迭代处理参数列表。那么,任何剩余的论点都是虚假的。很好
下面是另一种可能的方法,它保留了使用update()
的简单语法:
unknown\u args
是一个集合
,包含默认值中未出现的参数名称。处理未知或多个参数的另一个简单解决方案可以是:
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()
**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)
我喜欢只对必需的参数使用位置参数,对可能指定或可能未指定的参数使用kwargs,但使用默认值会有所帮助。kwargs很好,因为你可以按照你选择的任何顺序提交你的args。位置参数不能给你自由。你可以按你喜欢的顺序传递命名参数。如果你不使用名字,你只需要贴在位置上——在kwargs的情况下,你必须这样做。相反,使用命名参数而不是kwargs会给您额外的不使用名称的自由,但是,您必须遵守顺序。@Kekoa:您始终可以按照您选择的任何顺序提交命名参数。您不必使用**kwargs来获得这种灵活性。pylint将在中使用kwargs标记为坏形式。有人能解释为什么这是一个值得一提的违规行为吗?@hughdbrown可能是因为@Alex Martelli:我还没有找到一个答案声称kwargs与命名参数相同,更不用说更高级了。但好的话语对Py3k的改变,也是如此+1@Alex马尔泰利:非常感谢你的帮助
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()
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)