我来自静态语言的背景.有人可以解释(理想情况下通过示例)使用**kwargs而不是命名参数的真实世界优势吗?
对我来说,它似乎只是使函数调用更加模糊.谢谢.
Ale*_*lli 61
出于一系列原因,您可能希望接受几乎任意的命名参数 - 这就是**kw
表单允许您执行的操作.
最常见的原因是将参数正确传递给你正在包装的其他函数(装饰器就是这种情况的一种情况,但只有一个FAR!) - 在这种情况下,**kw
松开包装器和包装器之间的耦合,如包装器不必知道或关心所有wrappee的参数.这是另一个完全不同的原因:
d = dict(a=1, b=2, c=3, d=4)
Run Code Online (Sandbox Code Playgroud)
如果所有的名字都必须事先知道,那么这种方法显然不可能存在,对吧?顺便说一句,在适用的情况下,我更喜欢这种制作一个字符串的字符串:
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
Run Code Online (Sandbox Code Playgroud)
仅仅因为后者非常标点符号,因此可读性较差.
如果没有一个接受的优秀理由**kwargs
适用,那就不要接受它:就这么简单.IOW,如果没有充分的理由允许调用者传递具有任意名称的额外命名args,请不要允许这种情况发生 - 只需避免**kw
在def
语句的函数签名末尾放置一个表单.
至于在调用中的使用 **kw
,它允许你将一个必须传递的确切命名参数集合在一起,每个都有相应的值,在dict中,独立于单个调用点,然后在单个调用点使用该dict.相比:
if x: kw['x'] = x
if y: kw['y'] = y
f(**kw)
Run Code Online (Sandbox Code Playgroud)
至:
if x:
if y:
f(x=x, y=y)
else:
f(x=x)
else:
if y:
f(y=y)
else:
f()
Run Code Online (Sandbox Code Playgroud)
即使只有两种可能性(也是最简单的一种!),缺乏**kw
可能性使第二种选择绝对难以忍受和无法容忍 - 想象一下当有六种可能性时它会如何发挥作用,可能是稍微丰富的交互.没有**kw
,在这种情况下生活将是绝对的地狱!
Dan*_*man 40
您可能想要使用**kwargs
(和*args
)的另一个原因是您在子类中扩展现有方法.您希望将所有现有参数传递给超类的方法,但是要确保即使签名在将来版本中更改,您的类仍会继续工作:
class MySubclass(Superclass):
def __init__(self, *args, **kwargs):
self.myvalue = kwargs.pop('myvalue', None)
super(MySubclass, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)
Cat*_*lus 38
现实世界的例子:
装饰器 - 它们通常是通用的,因此您无法预先指定参数:
def decorator(old):
def new(*args, **kwargs):
# ...
return old(*args, **kwargs)
return new
Run Code Online (Sandbox Code Playgroud)
您想要使用未知数量的关键字参数进行魔术的地方.Django的ORM做到了这一点,例如:
Model.objects.filter(foo__lt = 4, bar__iexact = 'bar')
Run Code Online (Sandbox Code Playgroud)
Ned*_*der 11
有两种常见情况:
第一:你正在包装另一个带有许多关键字参数的函数,但你只是要传递它们:
def my_wrapper(a, b, **kwargs):
do_something_first(a, b)
the_real_function(**kwargs)
Run Code Online (Sandbox Code Playgroud)
第二:您愿意接受任何关键字参数,例如,在对象上设置属性:
class OpenEndedObject:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
foo = OpenEndedObject(a=1, foo='bar')
assert foo.a == 1
assert foo.foo == 'bar'
Run Code Online (Sandbox Code Playgroud)
**kwargs
如果您事先不知道参数的名称,那就很好。例如,dict
构造函数使用它们来初始化新字典的键。
Run Code Online (Sandbox Code Playgroud)dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
In [3]: dict(one=1, two=2)
Out[3]: {'one': 1, 'two': 2}
Run Code Online (Sandbox Code Playgroud)