18

I want to do:

try:
    do()
except:
    do2()
except:
    do3()
except:
    do4()

If do() fails, execute do2(), if do2() fails too, exceute do3() and so on.

best Regards

alwbtc
  • 28,057
  • 62
  • 134
  • 188
  • 4
    I have a feeling that describing your specific use case will lead to an answer with a more elegant solution... – Kenan Banks Dec 14 '12 at 07:58

7 Answers7

27

If you really don't care about the exceptions, you could loop over cases until you succeed:

for fn in (do, do2, do3, do4):
    try:
        fn()
        break
    except:
        continue

This at least avoids having to indent once for every case. If the different functions need different arguments you can use functools.partial to 'prime' them before the loop.

Fredrik Håård
  • 2,856
  • 1
  • 24
  • 32
14

I'd write a quick wrapper function first() for this.

usage: value = first([f1, f2, f3, ..., fn], default='All failed')

#!/usr/bin/env


def first(flist, default=None):

    """ Try each function in `flist` until one does not throw an exception, and
    return the return value of that function. If all functions throw exceptions,
    return `default` 

    Args: 
        flist - list of functions to try
        default - value to return if all functions fail

    Returns:
        return value of first function that does not throw exception, or
        `default` if all throw exceptions.

    TODO: Also accept a list of (f, (exceptions)) tuples, where f is the
    function as above and (exceptions) is a tuple of exceptions that f should
    expect. This allows you to still re-raise unexpected exceptions.
    """

    for f in flist:
        try:
            return f()
        except:
            continue
    else:
        return default

# Testing.

def f():
    raise TypeError

def g():
    raise IndexError

def h():
    return 1


# We skip two exception-throwing functions and return value of the last.
assert first([f, g, h]) == 1

assert first([f, g, f], default='monty') == 'monty'
Kenan Banks
  • 207,056
  • 34
  • 155
  • 173
5

It seems like a really odd thing to want to do, but I would probably loop over the functions and break out when there were no exception raised:

for func in [do, do2, do3]:
    try:
        func()
    except Exception:
        pass
    else:
        break 
gaqzi
  • 3,707
  • 3
  • 30
  • 30
  • Creat, but what's else here for? it seem redundant here. – AbstProcDo Aug 21 '18 at 16:33
  • The `else` will only execute when there isn't an exception. If there's an exception the for will continue whereas if there wasn't an exception the `break` will execute. :) A lot of statements in Python takes an `else` with the intention of "if everything went well, then do this". See the documentation for the `try` statement: https://docs.python.org/3/reference/compound_stmts.html#try – gaqzi Aug 22 '18 at 00:53
4

Here is the simplest way I found, just embed the try under the previous except.

try:
    do()
except:
    try:
        do2()
    except:
        do3()
sparrow
  • 10,794
  • 12
  • 54
  • 74
1

You should specify the type of the exception you are trying to catch each time.

try:
    do()
except TypeError: #for example first one - TypeError
    do_2()
except KeyError: #for example second one - KeyError
    do_3()

and so on.

alexvassel
  • 10,600
  • 2
  • 29
  • 31
  • If I don't know the type of the exception? – alwbtc Dec 14 '12 at 07:56
  • 2
    @alwbic: If you don't know the type of the exception, you don't know how to handle the exception. – BrenBarn Dec 14 '12 at 07:57
  • @alwbic I am really sure that you must know what type(s) of exception(s) do you expect. – alexvassel Dec 14 '12 at 07:57
  • 1
    I don't agree with you. I know that my statement will fail, but i don't know in which order they will fail. But I know what to do if it fails. – alwbtc Dec 14 '12 at 08:13
  • @alwbic: It is just a bad practice "Do something if something fails", you don't now why it fails. – alexvassel Dec 14 '12 at 08:15
  • @alwbic. I agree with you and you can do `except Exception: pass`. Something I always do when I develop is `except Exception as e: print(str(e))` to know what was the error. – aerijman Jul 12 '20 at 16:32
0

if you want multiple try statments you can do it like this, including the except statement. 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
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Engr Ali
  • 409
  • 1
  • 5
  • 13
-2
import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise