Calling a Python function with *args,**kwargs and optional / default arguments

后端 未结 4 1548
情深已故
情深已故 2020-11-27 14:06

In python, I can define a function as follows:

def func(kw1=None,kw2=None,**kwargs):
   ...

In this case, i can call func as:



        
4条回答
  •  感情败类
    2020-11-27 14:41

    If you are looking to do that in Python 2, I have found a workaround explained in this post, using a decorator.

    This decorator assigns default kwarg values if they are not strictly defined.

    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
    

    Result

    @force_kwargs(c=7, z=10)
    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',    (),       {'z': 10}
    f(1, 2, 3, 4, 5)                 #   1,   2, 7,   3, (4,5),       {'z': 10}
    f(1, 2, 3, b=0, c=9, f='F', z=5) #   1,   0, 9,   2,  (3,), {'f': 'F', 'z': 5}
    
    

    Variant

    If you want to use the default values as written in the function definition, you could access the argument default values using f.func_defaults, which lists the default values. You would have to zip them with the end of the f.__code__.varnames to match these default values with the variable names.

提交回复
热议问题