为什么在Python中使用**kwargs?相比命名参数有哪些实际优势?
我之前主要接触的是静态语言。有人能给我解释一下,使用**kwargs相比于命名参数在实际应用中有什么好处吗?最好能举个例子。
在我看来,这样的函数调用似乎会让事情变得更模糊。谢谢。
8 个回答
你可能还想使用 **kwargs
(和 *args
)的另一个原因是,当你在一个子类中扩展一个已有的方法时。你希望把所有现有的参数传递给父类的方法,但又想确保即使将来这个方法的参数列表发生变化,你的类仍然能够正常工作:
class MySubclass(Superclass):
def __init__(self, *args, **kwargs):
self.myvalue = kwargs.pop('myvalue', None)
super(MySubclass, self).__init__(*args, **kwargs)
你可能想要接受几乎任意的命名参数,这样做有很多原因,而这就是 **kw
形式的用处。
最常见的原因是将参数直接传递给你正在包装的其他函数(装饰器就是一个例子,但远不是唯一的情况!)——在这种情况下,**kw
让包装函数和被包装函数之间的关系变得不那么紧密,因为包装函数不需要知道或关心被包装函数的所有参数。还有一个完全不同的原因:
d = dict(a=1, b=2, c=3, d=4)
如果所有的参数名都必须提前知道,那么显然这种方法就不可能存在,对吧?顺便说一下,当可以使用时,我更喜欢用这种方式来创建一个字典,其键是字面字符串,而不是:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
因为后者的标点符号太多,读起来不太顺畅。
当没有任何很好的理由去接受 **kwargs
时,就不要接受:就是这么简单。换句话说,如果没有好的理由让调用者传递额外的命名参数,就不要允许这种情况发生——只需避免在函数定义的 def
语句的末尾放置 **kw
形式。
至于在调用中 使用 **kw
,这让你可以将必须传递的确切命名参数集合放在一个字典中,每个参数都有对应的值,而不需要在单个调用点上处理,然后在单个调用点使用这个字典。对比一下:
if x: kw['x'] = x
if y: kw['y'] = y
f(**kw)
和:
if x:
if y:
f(x=x, y=y)
else:
f(x=x)
else:
if y:
f(y=y)
else:
f()
即使只有两个可能性(而且是非常简单的那种!),没有 **kw
的情况下,第二种选择已经变得完全不可行和无法接受——想象一下当有六个可能性时,可能会有稍微复杂一点的交互……没有 **kw
,在这种情况下生活简直是绝对的地狱!
现实生活中的例子:
装饰器 - 通常它们是通用的,所以你不能提前指定参数:
def decorator(old):
def new(*args, **kwargs):
# ...
return old(*args, **kwargs)
return new
在你想要处理不确定数量的关键字参数的地方。比如,Django的ORM就做到了这一点,例如:
Model.objects.filter(foo__lt = 4, bar__iexact = 'bar')