Python 带有*args和**kwargs的默认参数

Python 带有*args和**kwargs的默认参数,python,python-2.7,Python,Python 2.7,在Python2.x中(我使用2.7),对于*args和**kwargs,使用默认参数的正确方法是什么? 我发现了一个与此主题如此相关的问题,但这是针对Python 3: 在那里,他们说这种方法有效: def func(arg1, arg2, *args, opt_arg='def_val', **kwargs): #... 在2.7中,它会导致一个语法错误。有没有推荐的方法来定义这样的函数? 我是这样工作的,但我想有更好的解决办法 def func(arg1, arg2, *arg

Python2.x中(我使用2.7),对于
*args
**kwargs
,使用默认参数的正确方法是什么?
我发现了一个与此主题如此相关的问题,但这是针对Python 3

在那里,他们说这种方法有效:

def func(arg1, arg2, *args, opt_arg='def_val', **kwargs):
    #...
在2.7中,它会导致一个
语法错误
。有没有推荐的方法来定义这样的函数?
我是这样工作的,但我想有更好的解决办法

def func(arg1, arg2, *args, **kwargs):
    opt_arg ='def_val'
    if kwargs.__contains__('opt_arg'):
        opt_arg = kwargs['opt_arg']
    #...

另一个问题中的语法是python3.x only,并且只指定关键字参数。它在python2.x上不起作用

对于python2.x,我会
pop
kwargs中的它:

def func(arg1, arg2, *args, **kwargs):
    opt_arg = kwargs.pop('opt_arg', 'def_val')

只需将默认参数放在
*args
之前:

def foo(a, b=3, *args, **kwargs):
现在,如果将其作为关键字参数或第二个位置参数传递,则将显式设置
b

示例:

foo(x) # a=x, b=3, args=(), kwargs={}
foo(x, y) # a=x, b=y, args=(), kwargs={}
foo(x, b=y) # a=x, b=y, args=(), kwargs={}
foo(x, y, z, k) # a=x, b=y, args=(z, k), kwargs={}
foo(x, c=y, d=k) # a=x, b=3, args=(), kwargs={'c': y, 'd': k}
foo(x, c=y, b=z, d=k) # a=x, b=z, args=(), kwargs={'c': y, 'd': k}
请特别注意,
foo(x,y,b=z)
不起作用,因为在这种情况下,
b
是按位置分配的



这段代码也适用于Python3。在Python3中,将默认arg放在
*args
之后,使其成为只能按名称而不是位置指定的“仅关键字”参数。如果您想在Python2中使用只包含关键字的参数,可以使用@mgilson。

另一种处理Python2.x的方法:

def foo(*args, **kwargs):
    if 'kwarg-name' not in kwargs.keys():
        kwargs['kwarg-name'] = 'kwarg-name-default-value'
    return bar(*args, **kwargs)

它处理任意的<代码> *ARGs<代码>,不同于@ NNSONE的回答。

粘贴得非常接近您的解决方案,同时试图使其更通用和更紧凑。我建议考虑这样的事情:

>>> def func(arg1, arg2, *args, **kwargs):
...     kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs)
...     #...
...     return arg1, arg2, args, kwargs_with_defaults

>>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'})

>>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})
import functools
def default_kwargs(**defaultKwargs):
    def actual_decorator(fn):
        @functools.wraps(fn)
        def g(*args, **kwargs):
            defaultKwargs.update(kwargs)
            return fn(*args, **defaultKwargs)
        return g
    return actual_decorator

您也可以使用这样的装饰器:

>>> def func(arg1, arg2, *args, **kwargs):
...     kwargs_with_defaults = dict({'opt_arg': 'def_val', 'opt_arg2': 'default2'}, **kwargs)
...     #...
...     return arg1, arg2, args, kwargs_with_defaults

>>> func('a1', 'a2', 'a3', 'a5', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'def_val', 'y': 'bar', 'x': 'foo'})

>>> func('a1', 'a2', 'a3', 'a5', opt_arg='explicit_value', x='foo', y='bar')
('a1', 'a2', ('a3', 'a5'), {'opt_arg2': 'default2', 'opt_arg': 'explicit_value', 'y': 'bar', 'x': 'foo'})
import functools
def default_kwargs(**defaultKwargs):
    def actual_decorator(fn):
        @functools.wraps(fn)
        def g(*args, **kwargs):
            defaultKwargs.update(kwargs)
            return fn(*args, **defaultKwargs)
        return g
    return actual_decorator
那么就做:

@default_kwargs(defaultVar1 = defaultValue 1, ...)
def foo(*args, **kwargs):
    # Anything in here
例如:

@default_kwargs(a=1)
def f(*args, **kwargs):
    print(kwargs['a']+ 1)

f() # Returns 2
f(3) # Returns 4

这个答案是什么的延伸

如果未严格定义默认kwarg值,则此装饰器将指定这些值

从functools导入包装
def force_kwargs(**默认kwargs):
def装饰器(f):
@包装(f)
def g(*args,**kwargs):
新参数={}
new_kwargs=defaultKwargs
varnames=f.\uuuuu代码\uuuuu.co\u varnames
新kwargs.update(kwargs)
对于defaultKwargs.items()中的k,v:
如果k在varnames中:
i=varnames.index(k)
new_args[(i,k)]=new_kwargs.pop(k)
#将新参数插入参数的正确位置。
完整参数=列表(参数)
对于已排序的i,k(new_args.keys()):

如果我与@yaccob的方法相似,但清晰简洁:

在Python 3.5或更高版本中:

def foo(a, b=3, *args, **kwargs):
  defaultKwargs = { 'c': 10, 'd': 12 }
  kwargs = { **defaultKwargs, **kwargs }
  print(a, b, args, kwargs)
  
  # Do something    

foo(1) # 1 3 () {'c': 10, 'd': 12}
foo(1, d=5) # 1 3 () {'c': 10, 'd': 5}
foo(1, 2, 4, d=5) # 1 2 (4,) {'c': 10, 'd': 5}
注意:您可以使用 在Python 2中

kwargs = merge_two_dicts(defaultKwargs, kwargs)
在Python 3.5中

kwargs = { **defaultKwargs, **kwargs }
在Python 3.9中

kwargs = defaultKwargs | kwargs  # NOTE: 3.9+ ONLY

是的,这是由于
*args
的歧义造成的。如果你想要一个只包含关键字的参数,你的方法是正确的。刚刚在上面的评论中得到了答案。(如果我想用不同的b调用函数,并且我想添加*args怎么办?)无论如何,在询问之前,我尝试了这个解决方案,但我也发现只有在定义了opt_arg之后,我只使用了kwargs,它才有效。@nneonno:我得到了你的示例,但是这种方式仍然不能给我们同时指定默认参数和*args的自由,就像Python3.x允许的那样,正如链接中所解释的;是吗?在填写
*args
时,不能单独使用默认参数。这就是为什么将该功能添加到Python 3中的原因。通常,Python 2中的默认参数被指定为一些明显的参数,如0或
None
,以便可以显式传入。它还指定了*args,在默认参数之前。这仍然是我遇到的最简洁的解释:从不显式调用
\uuuu包含\uuu
。始终在
中使用
在kwargs中使用“opt_arg”
。(更好的是:
kwargs.get('opt_arg','def_val')
,就像mgilson的回答一样)。如果使用有效的代码,即
'opt_arg'
而不是
'def_val'
而不是