142

I have a problem with my code in the try block. To make it easy this is my code:

try: code a code b #if b fails, it should ignore, and go to c. code c #if c fails, go to d code d except: pass 

Is something like this possible?

4
  • 2
    To be explicit, you want code c to be executed only when code b raises an exception? Commented Jun 26, 2013 at 14:06
  • All codes should be run, in one try block, even if they raise an exception. Commented Jun 26, 2013 at 14:41
  • 2
    You cannot have that. A try block is not there to suppress exceptions across all code executed. It'll let you catch the exception when it happens, but the rest of the block is never executed. Commented Jun 26, 2013 at 14:43
  • Okay, good to know. So per code an try block Commented Jun 26, 2013 at 14:50

11 Answers 11

207

You'll have to make this separate try blocks:

try: code a except ExplicitException: pass try: code b except ExplicitException: try: code c except ExplicitException: try: code d except ExplicitException: pass 

This assumes you want to run code c only if code b failed.

If you need to run code c regardless, you need to put the try blocks one after the other:

try: code a except ExplicitException: pass try: code b except ExplicitException: pass try: code c except ExplicitException: pass try: code d except ExplicitException: pass 

I'm using except ExplicitException here because it is never a good practice to blindly ignore all exceptions. You'll be ignoring MemoryError, KeyboardInterrupt and SystemExit as well otherwise, which you normally do not want to ignore or intercept without some kind of re-raise or conscious reason for handling those.

Sign up to request clarification or add additional context in comments.

8 Comments

Python's exception handling is just so ugly, it makes you write code that cries for C-style macros.
@Elazar: When your code starts to look like the above, you really want to rethink what you are doing. With context managers and some refactoring, most exception-handling code can be made much more readable and maintainable.
The question is, should I rethink it just because it is python so I must use both exceptions and indentation. Four simple operations, each should execute only if the last failed, and you get 4 levels of indentation. uh. If exceptions are good, their use should have been syntactically encouraged.
There is just not enough detail in the OP to go into possible alternatives.
@naught101: it's way, way too broad to give anything as focused as links to relevant context manager usage. The best I can think of is talks by Raymond Hettinger that demonstrate code refactorings that use context managers.
|
57

You can use fuckit module.
Wrap your code in a function with @fuckit decorator:

@fuckit def func(): code a code b #if b fails, it should ignore, and go to c. code c #if c fails, go to d code d 

6 Comments

Will this try every one or stop after the first that successfully runs?
Why would anyone use this?
@jfleach: because it does precisely what the OP asked for. And it's funny.
As @Austin commented in his question: this will try and excute every part of the code. It won't stop after the first succesfull one.
Now I want to see the project where someone actually uses this, lol.
|
22

Extract (refactor) your statements. And use the magic of and and or to decide when to short-circuit.

def a(): try: # a code except: pass # or raise else: return True def b(): try: # b code except: pass # or raise else: return True def c(): try: # c code except: pass # or raise else: return True def d(): try: # d code except: pass # or raise else: return True def main(): try: a() and b() or c() or d() except: pass 

6 Comments

I think a decorator would fit here.
If b fails (raises an exception), c will not be executed, nor will d.
it is Commented it is just there as a comment.... could write pass too..... edited it, better?
Okay that's what I thought, for each code I have to create a new try block. Because let's say I have several codes to be run, it should continue even if an exception occurs. Because what it does now, when the first exception occurs, when B fails, it will skip the other codes.Which is not what I want. Even if B fails it should try C, if C fails it should try D. No matter if error or not it should run through all lines. Hope it's better to understand now.
except: pass ... else: return True is an obscure way of implicitly saying except: return None ... else: return True. Better to be explicit.
|
10

If you don't want to chain (a huge number of) try-except clauses, you may try your codes in a loop and break upon 1st success.

Example with codes which can be put into functions:

for code in ( lambda: a / b, lambda: a / (b + 1), lambda: a / (b + 2), ): try: print(code()) except Exception as ev: continue break else: print("it failed: %s" % ev) 

Example with arbitrary codes (statements) directly in the current scope:

for i in 2, 1, 0: try: if i == 2: print(a / b) elif i == 1: print(a / (b + 1)) elif i == 0: print(a / (b + 2)) break except Exception as ev: if i: continue print("it failed: %s" % ev) 

Comments

6

You could try a for loop

 for func,args,kwargs in zip([a,b,c,d], [args_a,args_b,args_c,args_d], [kw_a,kw_b,kw_c,kw_d]): try: func(*args, **kwargs) break except: pass 

This way you can loop as many functions as you want without making the code look ugly

Comments

4

Lets say each code is a function and its already written then the following can be used to iter through your coding list and exit the for-loop when a function is executed without error using the "break".

def a(): code a def b(): code b def c(): code c def d(): code d for func in [a, b, c, d]: # change list order to change execution order. try: func() break except Exception as err: print (err) continue 

I used "Exception " here so you can see any error printed. Turn-off the print if you know what to expect and you're not caring (e.g. in case the code returns two or three list items (i,j = msg.split('.')).

Comments

2

I ran into this problem, but then it was doing the things in a loop which turned it into a simple case of issueing the continue command if successful. I think one could reuse that technique if not in a loop, at least in some cases:

while True: try: code_a break except: pass try: code_b break except: pass etc raise NothingSuccessfulError 

Comments

1

I use a different way, with a new variable:

continue_execution = True try: command1 continue_execution = False except: pass if continue_execution: try: command2 except: command3 

to add more commands you just have to add more expressions like this:

try: commandn continue_execution = False except: pass 

Comments

1

Building on kxr's answer (not enough rep to comment) you can use For/Else (see docs) to avoid checking the i value. The else clause only executes when the for finishes normally, so it gets skipped when the break executes

for i in 2, 1, 0: try: if i == 2: print(a / b) elif i == 1: print(a / (b + 1)) elif i == 0: print(a / (b + 2)) break except Exception as ev: continue else: print("it failed: %s" % ev) 

Comments

0

Like Elazar suggested: "I think a decorator would fit here."

# decorator def test(func): def inner(*args, **kwargs): try: func(*args, **kwargs) except: pass return inner # code blocks as functions @test def code_a(x): print(1/x) @test def code_b(x): print(1/x) @test def code_c(x): print(1/x) @test def code_d(x): print(1/x) # call functions code_a(0) code_b(1) code_c(0) code_c(4) 

output:

1.0 0.25 

Comments

0

assuming each code block returns non-null value. (where you should design it to be)

val = None try: val = func_a() except (AErr, ...): expt_a() # e.g. print('bad a') try: val = val or func_b() except (BErr, ...): expt_b() try: val = val or func_c() except (CErr, ...): expt_c() 

if there are plenty of these structures, further simplify as

func_errs_expt_list = [ [func_a, (AErr,...), expt_a], [func_b, (BErr,...), expt_b], [func_c, (CErr,...), expt_c], ... ] val = None for func, errs, expt in func_errs_expt_list: try: val = val or func(*args, **kwargs) except errs: expt(*args, **kwargs) 

introducing oo to prettify elements is possible

class BaseExceptionSafeBlock: @staticmethod def _try(*args, **kwargs): raise NotImplementedError('return non-null') @staticmethod def _expected_errors(*args, **kwargs): return tuple() # overridable @staticmethod def _except(e, *args, **kwargs): pass # overridable @classmethod def try(cls, *args, **kwargs): try: return cls._try(*args, **kwargs) except cls._expected_errors(*args, **kwargs) as e: cls._except(e, *args, **kwargs): return None class ABlock(BaseExceptionSafeBlock): @staticmethod def _try(*args, **kwargs): # do something and return it ... def execute(blocks, *args, **kwargs): for block in blocks: res = block.try(*args, **kwargs) if res is not None: return res return None val = execute([ABlock, ...], *args, **kwargs) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.