如何尝试平面样式的几种方法?

时间:2013-02-21 01:57:34

标签: python coding-style nested flat

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

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 个答案:

答案 0 :(得分: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:
    ...

答案 1 :(得分: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

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

答案 2 :(得分: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

答案 3 :(得分: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,或者完全忽略它们,或者跟踪它们并将异常列表附加到返回值和/或异常作为属性等等,如何修改它应该是非常明显的。

如果你想将参数传递给函数,那不是很明显,但仍然很容易。您只需要确定界面应该是什么。也许把一系列的callables作为第一个参数,然后是所有callables的参数:

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势头的争论,但是你可以找到更好的用途:

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

现在您可以使用更高阶的函数,例如mapany等。例如,map(tried, (trial_1, trial_2, trial_3, trial_4))为您提供了四个非投掷函数的序列,您可以{{ 1}}在Python中使用Haskell monad教程,这是让Python程序员和Haskell程序员都讨厌你的好方法。