3

如果我想尝试多种方法来避免一些错误,我可以写:

try:

    try:
        trial_1()
    except some_error:
        try:
            trial_2()
        except some_error:
            try:
                trial_3()
            ...
    print "finally pass"

except some_error:
    print "still fail"

但是太多的试验太多的嵌套,怎么写成扁平的样式呢?

4

4 回答 4

5

如果每次都是相同的例外,你可以这样做

for task in (trial_1, trial_2, trial_3, ...):
    try:
        task()
        break
    except some_error:
        continue

如果知道它是否成功很重要,那么添加它的最清晰方法可能是

successful = False
for task in (trial_1, trial_2, trial_3, ...):
    try:
        task()
        successful = True
        break
    except some_error:
        continue
if successful:
    ...
else:
    ...
于 2013-02-21T02:04:17.573 回答
1

假设 a)每个试验都不同,并且 b)它们都抛出相同的错误(因为这就是您的代码所说明的),并且 c)您知道所有试验函数的名称:

for t in (trial_1, trial_2, trial_3, trial_4):
    try:
        t()
        # if we succeed, the trial is over
        break
    except some_error:
        continue

这将遍历每个试验,在出现预期错误的情况下继续,如果试验成功则停止,并抛出任何其他异常。我认为这与您的示例代码的行为相同。

于 2013-02-21T02:06:46.697 回答
1

你可以这样做:

def trial1 (): 42 / 0
def trial2 (): [] [42]
def trial3 (): 'yoohoo!'
def trial4 (): 'here be dragons'

for t in [trial1, trial2, trial3, trial4]:
    print ('Trying {}.'.format (t.__name__) )
    try:
        t ()
        print ('Success')
        break
    except Exception as ex:
        print ('Failed due to {}'.format (ex) )
else:
    print ('Epic fail!')

输出是:

Trying trial1.
Failed due to division by zero
Trying trial2.
Failed due to list index out of range
Trying trial3.
Success
于 2013-02-21T02:07:37.217 回答
1

如果您需要多次执行此操作,您可以将 Hyperboreus 和其他人给出的答案打包为一个函数:

def first_success(*callables):
    for f in callables:
        try:
            return f()
        except Exception as x:
            print('{} failed due to {}'.format(f.__name__, x))
    raise RuntimeError("still fail")

然后,您只需要:

first_success(trial_1, trial_2, trial_3, trial_4)

如果您想要logging.info异常而不是print它们,或者完全忽略它们,或者跟踪它们并将异常列表附加到返回值和/或异常作为属性等,那么如何修改它应该很明显.

如果您想将参数传递给函数,那不是很明显,但仍然很容易。你只需要决定接口应该是什么。也许将一系列可调用对象作为第一个参数,然后是所有可调用对象的参数:

first_success((trial_1, trial_2, trial_3, trial_4), 42, spam='spam')

这很容易:

def first_success(callables, *args, **kwargs):
    for f in callables:
        try:
            return f(*args, **kwargs)
        except Exception as x:
            print('{} failed due to {}'.format(f.__name__, x))
    else:
        raise RuntimeError("still fail")

如果你并不总是需要这种模式,但你需要大量不完全一样的东西,你可能想要编写一个函数,将任何函数包装try. 我实际上已经构建了六次,然后意识到有一种更pythonic的方式来编写我的代码,这使得这个函数变得不必要,所以我唯一得到的用途是在与 Haskell snobs 的参数中,但是您可能会找到更好的用途:

def tried(callable, *args, **kwargs):
    try:
        return (callable(*args, **kwargs), None)
    except Exception as x:
        return (None, x)

现在你可以使用高阶map函数any如Haskell 程序员讨厌你。map(tried, (trial_1, trial_2, trial_3, trial_4))(f(x[0]) if x[1] is None else x for x in tried_sequence)

于 2013-02-21T02:47:07.403 回答