If you need to do this more than once, you can wrap up the answers Hyperboreus and others gave as a function:
def first_success(*callables):
for f in callables:
try:
return f()
except Exception as x:
print('{} failed due to {}'.format(f.__name__, x))
raise RuntimeError("still fail")
Then, all you need is:
first_success(trial_1, trial_2, trial_3, trial_4)
If you want to logging.info
the exceptions instead of print
them, or ignore them entirely, or keep track of them and attach the list of exceptions to the return value and/or exception as an attribute, etc., it should be pretty obvious how to modify this.
If you want to pass arguments to the functions, that's not quite as obvious, but still pretty easy. You just need to decide what the interface should be. Maybe take a sequence of callables as the first argument, and then all the callables' arguments after that:
first_success((trial_1, trial_2, trial_3, trial_4), 42, spam='spam')
That's easy:
def first_success(callables, *args, **kwargs):
for f in callables:
try:
return f(*args, **kwargs)
except Exception as x:
print('{} failed due to {}'.format(f.__name__, x))
else:
raise RuntimeError("still fail")
If you don't need exactly this pattern all the time, but you need a ton of not-quite-the-same things, you may want to instead write a function that just wraps any function in a try
. I've actually built this half a dozen times, and then realized there was a more pythonic way to write my code that made this function unnecessary, so the only use I've ever gotten out of it was in arguments with Haskell snobs, but you may find a better use for it:
def tried(callable, *args, **kwargs):
try:
return (callable(*args, **kwargs), None)
except Exception as x:
return (None, x)
Now you can use higher-order functions like map
, any
, etc. For example, map(tried, (trial_1, trial_2, trial_3, trial_4))
gives you a sequence of four non-throwing functions, and you can (f(x[0]) if x[1] is None else x for x in tried_sequence)
to work through a Haskell monad tutorial in Python, which is a good way to make both Python programmers and Haskell programmers hate you.