92

Python 2.x (私は 2.7 を使用) では、デフォルト引数を および で使用する適切な方法はどれ*argsですか**kwargs?
このトピックに関連する SO に関する質問を見つけましたが、それはPython 3に関するものです:
Calling a Python function with *args,**kwargs and optional / default arguments

そこでは、この方法が機能すると彼らは言います:

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

2.7 では、結果はSyntaxError. そのような関数を定義するための推奨される方法はありますか?
私はこの方法で動作しましたが、もっと良い解決策があると思います。

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

7 に答える 7

99

Just put the default arguments before the *args:

def foo(a, b=3, *args, **kwargs):

Now, b will be explicitly set if you pass it as a keyword argument or the second positional argument.

Examples:

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}

Note that, in particular, foo(x, y, b=z) doesn't work because b is assigned by position in that case.


This code works in Python 3 too. Putting the default arg after *args in Python 3 makes it a "keyword-only" argument that can only be specified by name, not by position. If you want a keyword-only argument in Python 2, you can use @mgilson's solution.

于 2013-03-08T19:45:36.450 に答える
60

The syntax in the other question is python3.x only and specifies keyword only arguments. It doesn't work on python2.x.

For python2.x, I would pop it out of kwargs:

def func(arg1, arg2, *args, **kwargs):
    opt_arg = kwargs.pop('opt_arg', 'def_val')
于 2013-03-08T19:45:23.387 に答える
0

この回答は、 Daniel Américo が提案したことの拡張です。

このデコレータは、厳密に定義されていない場合、デフォルトの kwarg 値を割り当てます。

from functools import wraps

def force_kwargs(**defaultKwargs):
    def decorator(f):
        @wraps(f)
        def g(*args, **kwargs):
            new_args = {}
            new_kwargs = defaultKwargs
            varnames = f.__code__.co_varnames
            new_kwargs.update(kwargs)
            for k, v in defaultKwargs.items():
                if k in varnames:
                    i = varnames.index(k)
                    new_args[(i, k)] = new_kwargs.pop(k)
            # Insert new_args into the correct position of the args.
            full_args = list(args)
            for i, k in sorted(new_args.keys()):
                if i <= len(full_args):
                    full_args.insert(i, new_args.pop((i, k)))
                else:
                    break
            # re-insert the value as a key-value pair
            for (i, k), val in new_args.items():
                new_kwargs[k] = val
            return f(*tuple(full_args), **new_kwargs)
        return g
    return decorator

結果

@force_kwargs(c=7)
def f(a, b='B', c='C', d='D', *args, **kw):
    return a, b, c, d, args, kw
#                               a    b  c    d  args      kwargs
f('r')                      # 'r', 'B', 7, 'D',   (),         {}
f(1,2,3)                    #   1,   2, 7,   3,   (),         {}
f(1, 2, 3, b=3, c=9, f='F') #   1,   3, 9,   2, (3,), {'f': 'F'}

変異体

f.func_defaults関数定義に記述されているデフォルト値を使用する場合は、デフォルト値をリストするを使用して引数のデフォルト値にアクセスできます。これらのデフォルト値を変数名と一致させるにzipは、 の最後を付けなければなりません。f.__code__.varnames

于 2020-08-18T21:54:17.837 に答える
0

Python 2.x で処理する別の方法:

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

*argsこれは、@nneonneoの回答とは異なり、基になる呼び出しに任意を渡すことを処理します。

于 2016-02-08T17:38:03.910 に答える