121

Can I return to executing the try block after exception occurs?

For example:

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
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
igor
  • 2,746
  • 3
  • 20
  • 24
  • 5
    You cannot return to a `try` block once interrupted, no. – Martijn Pieters Oct 22 '13 at 16:11
  • I think no. Some structure have to segment flow, and specify next point to execute at (`do_smth2` in this snippet) . – Jokester Oct 22 '13 at 16:11
  • 9
    possible duplicate of [A Pythonic way for "resume next" on exceptions?](http://stackoverflow.com/questions/18655481/a-pythonic-way-for-resume-next-on-exceptions) – Martijn Pieters Oct 22 '13 at 16:16
  • @MartijnPieters thats right, I googled too bad ;( – igor Oct 22 '13 at 16:20
  • if you aren't even going to check to see if do_smth1 took an exception or not... then do_smth1 should eat the exception itself and not pass it up. but probably, you do care, and this isn't the right flow. – Corley Brigman Oct 22 '13 at 16:45

12 Answers12

140

No, you cannot do that. That's just the way Python has its syntax. Once you exit a try-block because of an exception, there is no way back in.

What about a for-loop though?

funcs = do_smth1, do_smth2

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

Note however that it is considered a bad practice to have a bare except. You should catch for a specific exception instead. I captured for Exception because that's as good as I can do without knowing what exceptions the methods might throw.

  • 8
    At the very least catch Exception. This catches most exceptions but ignores SystemExit and KeyboardInterrupt which you almost never want to catch except possibly at the top level of your program. – Evan Oct 22 '13 at 17:00
  • this will not work if the do_smth1 internally has an exception where after catching it i want to continue inside do_smth1 right? – Vasanth Nag K V Feb 04 '19 at 05:31
  • Today for unknown reason my try/except gets out of the for loop entirely and I have clue why. MY code worked for the past two week and then today just decide to end the for loop... – JQTs Mar 23 '23 at 15:25
47

While the other answers and the accepted one are correct and should be followed in real code, just for completeness and humor, you can try the fuckitpy ( https://github.com/ajalt/fuckitpy ) module.

Your code can be changed to the following:

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

Then calling myfunc() would call do_smth2() even if there is an exception in do_smth1())

Note: Please do not try it in any real code, it is blasphemy

pankaj
  • 1,450
  • 14
  • 15
  • 2
    This is an ideal hack, although as you said, definitely not to be released in real code. The only down point (which I haven't managed to work around) is that this cannot access global variables, unlike the `try/except` methods, or the `with fuckit:` (The `fuckit` decorator seems more useful than the `with fuckit:`). – oliversm Aug 29 '17 at 09:23
  • 3
    This is true genius. Probably the product of a terrible work environment. – LaintalAy Nov 18 '19 at 09:07
25

You can achieve what you want, but with a different syntax. You can use a "finally" block after the try/except. Doing this way, python will execute the block of code regardless the exception was thrown, or not.

Like this:

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

But, if you want to execute do_smth2() only if the exception was not thrown, use a "else" block:

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

You can mix them too, in a try/except/else/finally clause. Have fun!

Lucas Ribeiro
  • 6,132
  • 2
  • 25
  • 28
14

'continue' is allowed within an 'except' or 'finally' only if the try block is in a loop. 'continue' will cause the next iteration of the loop to start.

So you can try put your two or more functions in a list and use loop to call your function.

Like this:

funcs = [f,g]
for func in funcs:
    try: func()
    except: continue

For full information you can go to this link

LaintalAy
  • 1,162
  • 2
  • 15
  • 26
LIU ZHIWEN
  • 143
  • 2
  • 6
8

You could iterate through your methods...

for m in [do_smth1, do_smth2]:
    try:
        m()
    except:
        pass
David Neale
  • 16,498
  • 6
  • 59
  • 85
8

one way you could handle this is with a generator. Instead of calling the function, yield it; then whatever is consuming the generator can send the result of calling it back into the generator, or a sentinel if the generator failed: The trampoline that accomplishes the above might look like so:

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

a generator that would be compatible with this would look like this:

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

Note that do_many_things() does not call do_smth*, it just yields them, and consume_exceptions calls them on its behalf

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • It looks clever but I am not sure if this technique has any practical advantages over simpler function `def catch_exceptions(function: Callable[[], Any]) -> Any: ...` and instead of using yeilds do directly: `a = catch_exceptions(do_smth1)` ... – pabouk - Ukraine stay strong Jun 04 '22 at 20:20
4

I don't think you want to do this. The correct way to use a try statement in general is as precisely as possible. I think it would be better to do:

try:
    do_smth1()
except Stmnh1Exception:
    # handle Stmnh1Exception

try:
    do_smth2()
except Stmnh2Exception:
    # handle Stmnh2Exception
rlms
  • 10,650
  • 8
  • 44
  • 61
3

Depending on where and how often you need to do this, you could also write a function that does it for you:

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

live_dangerously(do_smth1)
live_dangerously(do_smth2)

But as other answers have noted, having a null except is generally a sign something else is wrong with your code.

Dan
  • 4,312
  • 16
  • 28
2

This can be done with exec() in a custom function, a list of strings, and a for loop.

The function with exec():

def try_it(string):
    try:
        exec(string)
        print(f'Done: {string}')
    except:
        print(f'Error. Could not do: {string}')

More on exec():
exec(object)
This function supports dynamic execution of Python code. object must be either a string or a code object.

Example list of strings and for loop:

do_smth_list = ['do_smth1()', 'do_smth2()', 'do_smth3()'] 

for smth in do_smth_list:
    try_it(smth)
wisedesign
  • 21
  • 2
2

This definitely isn't the cleanest way of doing it, but you can put it in a while loop with a variable set to true, and when it runs the function successfully it sets the variable to false, whereas if it fails it keeps the variable set to true.

x = True
while x == True:
    try:
        do_smth1()
        do_smth2()
        x = False
    except Exception:
        x = True

This way what happens is that the while loop will keep on looping the try except section again and again until it works, in which x is set to false and the loop stops

Also, you can implement a break in the while loop instead of basing it on a variable, for example:

while True:
    try:
        do_smth1()
        do_smth2()
        break
    except Excpetion:
        pass

P.S It is good ettiquete to put a specific exception for the except section, instead of leaving it for any exception. It makes the code cleaner and is more sensible when managing errors especially in bigger projects

1

special_func to avoid try-except repetition:

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) 

Run code:

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)

Output looks like:

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

To convert to variables:

locals().update(solution)

Variables would look like:

AddFunc = 16, MulFunc = 54, SubFunc = NameError("name 'p' is not defined")
JonathanDavidArndt
  • 2,518
  • 13
  • 37
  • 49
DeWil
  • 362
  • 3
  • 10
0

If do_smth1() worked, then do_smth2() will not be tried.

try:
    x=do_smth1()
except:
    try:
        x=do_smth2()
    except:
        x="Both Failed"

print (x)