向回调传递额外的可选参数,而不会破坏现有的回调

时间:2019-01-08 22:03:35

标签: python python-3.x python-3.3

我有一个接受回调的API方法。回调需要一个参数。

我希望此方法将第二个参数传递给接受它的回调。但是,我必须与仅接受原始参数的回调保持兼容性。 (实际上,我希望大多数用户不会在意这个附加参数,因此强迫他们明确地忽略它会很烦人。)

我知道可以使用inspect完成此操作。我想知道是否有一个“惯用的”或常用的解决方案不太重。

3 个答案:

答案 0 :(得分:4)

我认为您可以使用__code__查看回调所需的参数。

if callback.__code__.co_argcount == 2:
    callback(arg1, arg2)
else:
    callback(arg1)

此代码未经测试,但可以正常工作。

答案 1 :(得分:1)

一种更简单的解决方案是使用try块先尝试使用第二个参数调用回调,然后再退回到except块中仅使用一个参数进行调用:

try:
    callback(first, second)
except TypeError as e:
    if e.__traceback__.tb_frame.f_code.co_name != 'func_name':
        raise
    callback(first)

答案 2 :(得分:-1)

使用函数包装器:

from inspect import signature, Parameter

def ignore_extra_arguments(function):
    positional_count = 0
    var_positional = False
    keyword_names = set()
    var_keyword = False

    for p in signature(function).parameters.values():
        if p.kind == Parameter.POSITIONAL_ONLY:
            positional_count += 1
        elif p.kind == Parameter.POSITIONAL_OR_KEYWORD:
            positional_count += 1
            keyword_names.add(p.name)
        elif p.kind == Parameter.VAR_POSITIONAL:
            var_positional = True
        elif p.kind == Parameter.KEYWORD_ONLY:
            keyword_names.add(p.name)
        elif p.kind == Parameter.VAR_KEYWORD:
            var_keyword = True

    if var_positional:
        new_args = lambda args: args
    else:
        new_args = lambda args: args[:positional_count]

    if var_keyword:
        new_kwargs = lambda kwargs: kwargs
    else:
        new_kwargs = lambda kwargs: {
            name: value for name, value in kwargs.items()
            if name in keyword_names
        }

    def wrapped(*args, **kwargs):
        return function(
            *new_args(args),
            **new_kwargs(kwargs)
        )

    return wrapped

它可以工作,但是有点蛮力。

一个简单的版本,假设function没有关键字或可变参数:

from inspect import signature

def ignore_simple(function):
    count = len(signature(function).parameters)
    return lambda *args: function(*args[:count])