20

Snippet 1

do_magic() # Throws exception, doesn't execute do_foo and do_bar
do_foo()
do_bar()

Snippet 2

try:
    do_magic() # Doesn't throw exception, doesn't execute do_foo and do_bar
    do_foo() 
    do_bar()
except:
    pass

Snippet 3

try: do_magic(); except: pass
try: do_foo()  ; except: pass
try: do_bar()  ; except: pass

Is there a way to write code snippet 3 elegantly?

  • if do_magic() fails or not, do_foo() and do_bar() should be executed.
  • if do_foo() fails or not, do_bar() should be executed.

In Basic/Visual Basic/VBS, there's a statement called On Error Resume Next which does this.

Elmo
  • 6,409
  • 16
  • 72
  • 140
  • 4
    And `On Error Resume Next` is a crime against control flow! – jonrsharpe Sep 26 '14 at 12:26
  • Can you decorate those function like here? http://stackoverflow.com/a/9386604/1532474 – Dominik Neise Sep 26 '14 at 12:28
  • You would be interested in [Exhibit A](http://stackoverflow.com/questions/18887163/python-resuming-program-at-line-number-in-the-context-before-an-exception-using) and [Exhibit B](http://stackoverflow.com/questions/18945680/dynamic-semantic-errors-in-python). – Veedrac Sep 27 '14 at 07:03
  • 1
    For newbies, it should be said Snippet 3 does not work. As a rule, I find Python permits one ":" on a line. See my new answer just now. @jonrsharpe, that's just silly. I use python now, and like the OP, I find many things in VBA that have no simple replacement in any other language. VBA error checking is pretty profound if you know how to use it. – www-0av-Com Feb 20 '18 at 14:28

7 Answers7

19

In Python 3.4 onwards, you can use contextlib.suppress:

from contextlib import suppress

with suppress(Exception): # or, better, a more specific error (or errors)
    do_magic()
with suppress(Exception):
    do_foo()
with suppress(Exception):
    do_bar()

Alternatively, fuckit.

Aaron Christiansen
  • 11,584
  • 5
  • 52
  • 78
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
12

If all three functions accept same number of parameters:

for f in (do_magic, do_foo, do_bar):
    try:
        f()
    except:
        pass

Otherwise, wrap the function call with lambda.

for f in (do_magic, lambda: do_foo(arg1, arg2)):
    try:
        f()
    except:
        pass
falsetru
  • 357,413
  • 63
  • 732
  • 636
  • I thought about this but when the code gets polluted with if statements, loops and what not this doesn't work right. – Elmo Sep 26 '14 at 12:23
  • @Zuck, This is the best I can think of. I wish others come up with better idea. – falsetru Sep 26 '14 at 12:26
1

If there are no parameters...

funcs = do_magic, do_foo, do_bar

for func in funcs:
    try:
        func()
    except:
        continue
Keith Aymar
  • 876
  • 7
  • 10
1

If you are the one coding the fucntions, why not program the functions to return status codes? Then they will be atomic and you wont have to capture the error in the main section. You will also be able to perform roll back or alternate coding on failure.

def do_magic():
    try:
        #do something here
        return 1
    except:
        return 0

in main program..

if do_magic() = 0:
   #do something useful or not...

if do_foo() = 0:
   #do something useful or not...

if do_bar() = 0:
   #do something useful or not...
Keith Aymar
  • 876
  • 7
  • 10
  • The question asked for every line being caught (not every function), and unless you wrap every line in a function, this does not do what the question asked. – Anonymous Mar 20 '20 at 23:14
  • The functions maybe in another package, we don't want to have to waste time wrapping up wrappers. With Python, many of us are just using quick scripts to get work done quickly. – Graham Monkman Feb 03 '23 at 11:32
0

you could try a nested ´try´ loop, alltho that might not be as elegantly pythonic as you might want. the ´lambda´ solution is is also a good way to go, did not mention because it was done in the previous answer

edit:

try:
    do_magic()
finally:
    try:
        do_foo()
    finally:
        try:
            do_bar()
        except:
            pass

edit 2:

well damnnit, this answer just got posted seconds beforehand again :|

Mazimer
  • 33
  • 7
  • As already commented in m170897017's answer, if do_magic() does not raise an exception, other function calls will not be executed. – falsetru Sep 26 '14 at 12:28
  • the OP seems to indicate he does not want them to execute if do_magic() works its magic without fail – Mazimer Sep 26 '14 at 12:31
  • No. OP want next statement to be executed regardless of success/failure of the preceding statement. – falsetru Sep 26 '14 at 12:35
0

A lot of ident, but it works

try:
    do_magic()
finally:
    try:
        do_foo()
    finally:
        try:
            do_bar()
        finally:
            pass
xecgr
  • 5,095
  • 3
  • 19
  • 28
0

In the question, Snippet 3 does not work but will work if you don't mind splitting each line over two lines...

try: do_magic()
except: pass
try: do_foo()
except: pass
try: do_bar()
except: pass

A working example..

import sys
a1 = "No_Arg1"
a2 = "No_Arg2"
a3 = "No_Arg3"
try: a1 = sys.argv[1]
except: pass
try: a2 = sys.argv[2]
except: pass
try: a3 = sys.argv[3]
except: pass

print a1, a2, a3

..if you save this to test.py and then at a CMD prompt in windows simply type test.py it will return No_Arg1 No_Arg2 No_Arg3 because there were no arguments. However, if you supply some arguments, if type test.py 111 222 it will return 111 222 No_Arg3 etc. (Tested - Windows 7, python2.7).

IMHO this is far more elegant than the nesting example replies. It also works exactly like On Error Resume Next and I use it when translating from VB6. One issue is that the try lines cannot contain a conditional. I have found that as a rule, python cannot contain more than one : in a line. That said, it simply means splitting the statement over 3 lines etc.

www-0av-Com
  • 707
  • 10
  • 14