开发者

Pass kwargs with invalid key=value pairs to function

The following code:

def f(a=1):
    pass

kwargs = {}
kwargs['a'] = 1
kwargs['b'] = 2

f(**kwargs)

(correctly) raises an Exception:

Traceback (most recent call last):
  File "tt.py", line 8, in <module>
    f(**kwargs)
TypeError: f() got an unexpected keyword argument 'b'

Is there a way, with functools or other, to get around this and figure out which arguments didn't get used by t开发者_Go百科he function in order to be able to pass them to another function? For example, I might have another function:

def g(a=None, b=None):
    pass

which I want to call after, with e.g.

g(**kwargs)

but I only want b to be passed because a was already 'used up' in the previous function.

Now I know that this is not ideal coding, but there are cases where it can come in handy, and it is actually easy to explain to the user, e.g. "Additional parameters will be passed to f, and any parameters not passed to f will be passed to g".


I am a bit astonished that you ask this question and fear that you are doing something you may regret.

Are you trying to call different methods with the same dictionary providing all arguments combined? If so, then the complexity required to handle this case shouldn't be dealt with in the called methods but the calling code, e.g. by tailoring the kwargs to the specific method to be called:

def f(a=1):
    pass

call_tailored_args(f, kwargs)

The helper function would be implemented like this:

import inspect

def tailored_args(f, kwargs):
    relevant_args = {k: v in kwargs if k in inspect.getargspec(f).args}
    f(**relevant_args)


Is this what you mean?

def g(**kwargs):
    a=kwargs.pop('a',None)    
    b=kwargs.pop('b',None)
    print(a,b)
def f(**kwargs):
    a=kwargs.pop('a',None)
    print(a)
    g(**kwargs)

kwargs = {'a':1,'b':2}

f(**kwargs)
# 1
# (None, 2)


You can use a decorator to remove the extra kwargs keys:

def remove_args(fx):
    def wrap(**kwargs):
        kwargs2 = copy.copy(kwargs)

        ret = None
        done = False

        while not done:
            try:
                ret = fx(**kwargs2)
                done = True
            except TypeError, ex:
                key = re.findall("\'(\w+)\'", ex.message)[0]
                del kwargs2[key]              # Remove offending key
                # print "%s removing %s" % (fx.__name__, key)

        return ret

    return wrap


@remove_args
def f1(a=1):
    return "f1-ret"

@remove_args
def f2(b=1):
    return "f2-ret"

kwargs = {"a": 1, "b": 2, "c": 3}

print f1(**kwargs)
print f2(**kwargs)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜