首页 > 解决方案 > 尝试函数调用的变化,直到完成而不抛出异常

问题描述

尝试不同的功能直到不抛出异常有关

我需要按顺序进行多个函数调用,直到一个返回而不抛出异常。这些函数根据输入数据执行不同的方法来解决问题。

在长格式中,以下工作:

try:
    answer = method1(data, x, y, z)
except MyException:
    try:
        answer = method2(data, x, y, z, factor=1.0)
    except MyException:
        try:
            answer = method3(data, x, y, z, factor=2.0)
        except MyException:
            ...

在伪代码中,我的目标是更干净、更容易扩展:

tryUntilOneWorks:
    answer = method1(data, x, y, z)
    answer = method2(data, x, y, z, factor=1.0)
    answer = method2(data, x, y, z, factor=2.0)
    answer = method3(a, b, c)
    answer = method4(data)
except:
    # No answer found

标签: pythonpython-3.x

解决方案


Aran-Fey 的建议可能是最简单的解决方案:动态创建函数对象列表,以您想要的方式调用您想要的方法:

def find_one_that_works(data, a, b, c, x, y, z, factor1, factor2):
    methods = [
        lambda: method1(data, x, y, z),
        lambda: method2(data, x, y, z, factor=1.0),
        lambda: method2(data,x,y,z,factor=2.0),
        lambda: method3(a, b, c),
        lambda: method4(data),
    ]
    for method in methods:
        try:
            return method()
        except MyException:
            pass
    raise MyException('All methods failed')

这需要大量的硬编码,所以我会推荐一些更通用的东西。您可以传入所有可能的参数、关键字或其他参数,以及如何将它们应用于每个函数的规范:

def find_one_that_works(methods, specs, *args, **kwargs):
    def get(k):
        return kwargs[k] if isinstance(k, str) else args[k]

    for method, (arg_spec, kwarg_spec) in zip(methods, specs):
        ar = [get(k) for k in arg_spec]
        kw = {k: get(v) for k, v in kwarg_spec.items()}
        try:
            return method(*ar, **kw)
        except MyException:
            pass
    raise MyException('None succeeded')

这允许您指定位置参数的选择元组和关键字参数的选择映射,这些参数将从您传递给函数的所有内容中提取。您问题中的示例将被称为:

methods = [method1, method2, method2, method3, method4]
specs = [
    ((0, 4, 5, 6), {}),
    ((0, 4, 5, 6), {'factor': 7}),
    ((0, 4, 5, 6), {'factor': 8}),
    ((1, 2, 3), {}),
    ((0,), {})
]
find_one_that_works(methods, specs, data, a, b, c, x, y, z, 1.0, 2.0)

好消息是你也可以用这种方式命名所有参数。以下与上述相同:

methods = [method1, method2, method2, method3, method4]
specs = [
    (('data', 'x', 'y', 'z'), {}),
    (('data', 'x', 'y', 'z'), {'factor': 'factor1'}),
    (('data', 'x', 'y', 'z'), {'factor': 'factor2'}),
    (('a', 'b', 'c'), {}),
    (('data',), {})
]
find_one_that_works(methods, specs,
                    data=data, a=a, b=b, c=c,
                    x=x, y=y, z=z, factor1=1.0, factor2=2.0)

推荐阅读