将无效的key=value对作为kwargs传递给函数

6 投票
3 回答
3908 浏览
提问于 2025-04-17 00:27

以下代码:

def f(a=1):
    pass

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

f(**kwargs)

(正确地)引发了一个异常:

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

有没有办法,比如用functools或者其他方法,来绕过这个问题,找出哪些参数没有被函数使用,以便可以把它们传递给另一个函数?比如,我可能还有另一个函数:

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

我想在之后调用它,比如:

g(**kwargs)

但我只想传递 b,因为 a 在之前的函数中已经被“用掉”了。

我知道这样写代码并不是最理想的,但有些情况下这样做会很方便,而且其实也很容易向用户解释,比如“额外的参数会传递给f,而没有传递给f的参数会传递给g”。

3 个回答

1

你可以使用一个装饰器来去掉多余的关键字参数(kwargs)键:

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)
4

这是不是你想表达的意思?

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)
5

我有点惊讶你会问这个问题,担心你可能会做出让自己后悔的事情。

你是不是想用同一个字典来调用不同的方法,并且这个字典里包含了所有的参数?如果是这样的话,处理这种情况的复杂性应该在调用的代码中解决,而不是在被调用的方法里。比如说,可以根据要调用的方法来调整 kwargs

def f(a=1):
    pass

call_tailored_args(f, kwargs)

这个辅助函数可以这样实现:

import inspect

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

撰写回答