Python 的抽象使用导致 TypeError

Abstract uses of Python result in TypeError

以下面的代码为例:

def inner(a, b):
    return (a, b)

def outer(func, *args, **kwargs):
    return func(*args, **kwargs)

当执行 outer(inner, 1, b=2) 时 returns 正确的值 (1, 2).

如何使用作为 kwargs 传递的参数 a 和作为 arg 传递的参数 b 调用同一个函数?即:outer(inner, 1, a=2)

运行 outer(inner, 1, a=2) 引发异常:TypeError: inner() got multiple values for argument 'a'.

如何包装函数以便传递参数"out of order"?

您可以inspect 方法并获取参数名称。然后,您生成所有显式传递的其余参数的列表。喜欢:

>>> list(inspect.signature(inner).parameters)
['a', 'b']

因此您可以生成剩余参数列表:

import inspect

def outer(func, *args, **kwargs):
    remain = list(par for par in inspect.signature(func).parameters if par not in kwargs)
    kwargs.update(zip(remain,args))
    return func(**kwargs)

所以它将忽略所有显式声明的变量,然后zip剩余的未命名变量(此处剩下的一个是 b) 和 未命名的值 .

请注意,如果您这样指定

def inner3(a,b,c):
    return (a,b,c)

如果您指定 outer(inner,1,2,a=4),则需要将未命名变量指定为 (b,c)(该顺序),因此 b = 1c = 2。如果您指定 outer(inner,1,2,b=4),则 a = 1c = 2。此外,如果您指定两个参数,此处未命名的参数将与其余参数统一,因此 outer(inner,1,a=2,c=4) 将导致 b=1.

话虽这么说,但我认为不是一个好主意。这种行为很难理解,所以人们往往会犯错误。 Python 的设计者没有选择在解释器级别支持此功能可能有充分的理由。当然,您可能有(很好的)理由想要这样做,但在这样做之前请三思。