2013-10-22 117 views
21

发生异常后,可以返回执行try-block吗? (我们的目标是少写) 例如:python捕获异常,并继续尝试块

try: 
    do_smth1() 
except: 
    pass 

try: 
    do_smth2() 
except: 
    pass 

VS

try: 
    do_smth1() 
    do_smth2() 
except: 
    ??? # magic word to proceed to do_smth2() if there was exception in do_smth1 
+0

不能返回到'try'块一旦中断,没有。 –

+0

我觉得没有。某些结构必须对流进行分段,并指定下一个要执行的点(此代码段中的“do_smth2”)。的 – Jokester

+3

可能重复[A Python的方式为“恢复下一个”例外?](http://stackoverflow.com/questions/18655481/a-pythonic-way-for-resume-next-on-exceptions) –

回答

27

不,你不能这样做。这就是Python的语法。一旦你因为例外而退出一个try-block,就没有办法回来了。

虽然for循环呢?

funcs = do_smth1, do_smth2 

for func in funcs: 
    try: 
     func() 
    except Exception: 
     pass # or you could use 'continue' 

但请注意,裸露的except被认为是不好的做法。你应该赶上一个特定的例外。我捕获了Exception,因为如果不知道这些方法可能抛出什么异常,我就可以做到这一点。

+0

最起码捕获异常。这捕获最异常,但忽略了SystemExit和一个KeyboardInterrupt你几乎从来没有想除了可能赶在你的程序的顶层。 – Evan

4

你可以通过你的方法重复...

for m in [do_smth1, do_smth2]: 
    try: 
     m() 
    except: 
     pass 
1

我不认为你想这样做。一般情况下使用try声明的正确方法尽可能精确。我认为这将是更好的事情可做:

try: 
    do_smth1() 
except Stmnh1Exception: 
    # handle Stmnh1Exception 

try: 
    do_smth2() 
except Stmnh2Exception: 
    # handle Stmnh2Exception 
1

根据您需要的位置和频率要做到这一点,你也可以编写一个函数,它会为你:

def live_dangerously(fn, *args, **kw): 
    try: 
     return fn(*args, **kw) 
    except Exception: 
     pass 

live_dangerously(do_smth1) 
live_dangerously(do_smth2) 

但在其他答案已经注意到,有一个空值except通常表示你的代码有其他错误。

5

你可以实现你想要的,但使用不同的语法。 try/except后可以使用“finally”块。这样做,无论抛出异常,python都会执行代码块。

像这样:

try: 
    do_smth1() 
except: 
    pass 
finally: 
    do_smth2() 

但是,如果你想要执行do_smth2()只如果没有抛出的异常,请使用 “其他” 块:

try: 
    do_smth1() 
except: 
    pass 
else: 
    do_smth2() 

你可以将它们混合在try/except/else/finally子句中也是如此。 玩得开心!

3

你可以处理这种情况的一种方法是使用发电机。不要调用函数,而要调用它;那么无论在消费发生器可以发送主叫它放回发生器,或定点的结果,如果发电机失败:那上面完成蹦床看起来可能是这样:

def consume_exceptions(gen): 
    action = next(gen) 
    while True: 
     try: 
      result = action() 
     except Exception: 
      # if the action fails, send a sentinel 
      result = None 

     try: 
      action = gen.send(result) 
     except StopIteration: 
      # if the generator is all used up, result is the return value. 
      return result 

发电机,将是兼容这个应该是这样的:

def do_smth1(): 
    1/0 

def do_smth2(): 
    print "YAY" 

def do_many_things(): 
    a = yield do_smth1 
    b = yield do_smth2 
    yield "Done" 
>>> consume_exceptions(do_many_things()) 
YAY 

注意do_many_things()通话do_smth*,它只是得到他们,consume_exceptions叫他们代其

12

而其他的答案和接受的一个是正确的,应该遵循在真正的代码,只是为了保持完整性和幽默,你可以尝试fuckitpyhttps://github.com/ajalt/fuckitpy)模块。

您的代码可以更改为以下几点:

@fuckitpy 
def myfunc(): 
    do_smth1() 
    do_smth2() 

然后调用myfunc()会打电话do_smth2()即使在do_smth1())

注意一个例外:请不要尝试在任何真正的代码,这是亵渎

+0

这是一个理想的黑客,尽管如你所说,绝对不会被真正的代码释放,唯一的缺点是(我没有设法解决),它不能访问全局变量,不像'try/except'方法,或者'with fuckit:'('fuckit'装饰者似乎比'fuckit:'更有用)。 – oliversm

0

special_func以避免尝试 - 除了重复:

def special_func(test_case_dict): 
    final_dict = {} 
    exception_dict = {} 

    def try_except_avoider(test_case_dict): 

     try: 
      for k,v in test_case_dict.items(): 
       final_dict[k]=eval(v) #If no exception evaluate the function and add it to final_dict 

     except Exception as e: 
      exception_dict[k]=e #extract exception 
      test_case_dict.pop(k) 
      try_except_avoider(test_case_dict) #recursive function to handle remaining functions 

     finally: #cleanup 
      final_dict.update(exception_dict) 
      return final_dict #combine exception dict and final dict 

    return try_except_avoider(test_case_dict) 

运行代码:

def add(a,b): 
    return (a+b) 
def sub(a,b): 
    return (a-b) 
def mul(a,b): 
    return (a*b) 

case = {"AddFunc":"add(8,8)","SubFunc":"sub(p,5)","MulFunc":"mul(9,6)"} 
solution = special_func(case) 

输出的样子:

{'AddFunc': 16, 'MulFunc': 54, 'SubFunc': NameError("name 'p' is not defined")} 

要转换为变量:

locals().update(solution) 

变量会是什么样子:

AddFunc = 16, MulFunc = 54, SubFunc = NameError("name 'p' is not defined")