How to repeat something on exception in python?

What is the most elegant way to repeat something after it throws an exception in python?

I have something like this [example pseudo code]:

try: do_some_database_stuff() except DatabaseTimeoutException: reconnect_to_database() do_some_database_stuff() # just do it again 

But imagine if I don't have a nice feature, but a lot of code. Duplicated code is not very nice.

So, I think this is a little better:

 while True: try: do_some_database_stuff() break except DatabaseTimeoutException: reconnect_to_database() 

This is good enough if the exception really fixes the problem. If not, I need a counter to prevent an indefinite loop:

 i = 0 while i < 5: try: do_some_database_stuff() break except DatabaseTimeoutException: reconnect_to_database() i += 1 

But then I don't know if this works like this:

 while i <= 5: try: do_some_database_stuff() break except DatabaseTimeoutException: if i != 5: reconnect_to_database() else: raise DatabaseTimeoutException i += 1 

As you can see, this is starting very unpleasantly.

What is the most elegant way to express this logic?

  • try something
  • If this fails, correct
  • try a few more times including fix
  • if it continues to fail gives me an error to prevent an indefinite loop
+6
source share
2 answers

You can use the for-else loop:

 for ii in range(5): try: do_some_database_stuff() break except DatabaseTimeoutException: reconnect_to_database() else: raise DatabaseTimeoutException 

Or, without:

 for ii in range(5): try: do_some_database_stuff() break except DatabaseTimeoutException: if ii == 4: raise reconnect_to_database() 
+6
source

I personally am not a fan of the for-else construct. I do not find this intuitive. The first time I read this, I thought what it means to "do for a loop (...), if iterable was empty, then ...".

You must put your code inside the function. If do_some_database_stuff() succeeds, you can use the return statement to return from the function.

eg.

 def try_to_do_some_database_stuff(): for i in range(num_times): try: return do_some_database_stuff() except DatabaseTimeoutException: reconnect_to_database() raise DatabaseTimeoutException 

If you use this design too much, you can make it more general.

 def try_to_do(func, catch, times=2, on_exception=None): for i in range(times): try: return func() except catch: if on_exception: on_exception() raise catch try_to_do(do_some_database_stuff, catch=DatabaseTimeoutException, times=5, on_exception=reconnect_to_database) 

You can use functools.partial if you need to pass arguments to your functions.

+1
source

Source: https://habr.com/ru/post/977867/


All Articles