[Python-ideas] Retrying EAFP without DRY

Steven D'Aprano steve at pearwood.info
Sat Jan 21 08:47:46 CET 2012


Mike Meyer wrote:

> A single new keyword/clause, "retry". It has the same syntax as an
> "except" clause, can be used anywhere "except" can be used, and can be
> intermingled with them in the same try statement. There's probably a
> better syntax, but this is easy to describe.

> The behavior change from except is that instead of exiting the "try"
> statement when the "retry" clause ends, it restarts the try

This sounds like retry should be a flow-control statement, like continue or 
break, not a block. E.g.:

try:
     something()
except ValueError:
     if condition: retry
     else: raise


"retry" will jump back to the start of the try block -- a limited form of 
GOTO, with all the pros and cons of this.



> clause. In python, this code:
>
>     try:
>         # try block
>     except:
>         # except block
>     retry:
>         # retry block
>     else:
>         # else block
>     finally:
>         # finally block
> 
> Would provide the same behavior as this code:
> 
>     while True:
>         try:
>             # try block
>         except:
>             # except block
>         retry:
>             # retry block
>         else:
>             # else block
>         finally:
>             # finally block
>             break

Um, you're trying to explain the behaviour of retry here, but your Python code 
includes a retry. This is one case where recursion is NOT your friend.



> Where except & retry can be repeated, include exceptions to check
> against, and intermixed with each other. The break would propagate up
> to the else block and any except blocks if there was no finally. If
> there's no else, the break from it winds up at the end of the try.

None of your explanation is clear to me.

Under what circumstances will the retry block be executed? E.g. given:

   try:
       len(None)
   except TypeError:
       print("spam spam spam")
   retry:
       print("a")

what will happen?

How about these?

   #1
   try:
       len(None)
   retry:
       print("a")
   except TypeError:
       print("spam spam spam")

   #2
   try:
       len(None)
   except TypeError:
       print("spam spam spam")
   retry:
       print("a")
   except ValueError:
       print("this never gets called")
   retry:
       print("b")

   #3
   try:
       len(None)
   except TypeError:
       print("spam spam spam")
   retry:
       print("a")
   retry:
       print("b")


> The use case, as mentioned, is avoiding doing EAFP without repeating
> the code in the exception handler. I.e., the choices without retry
> are things like (LBYL):

I think that the idiom of a while or for loop is easy enough to read and write:

for _ in range(5):  # retry five times
     try:
         do_something(x)
     except SpamError:
         x = fix_up(x)
     else:
         break
else:
     raise HamError("tried 5 times, giving up now")


I just wish that break and continue could be written outside of a loop, so you 
can factor out common code:

def do_the_thing(x):
     try:
         do_something(x)
     except SpamError:
         x = fix_up(x)
     else:
         break

def try_repeatedly(n, func):
     for _ in range(n):
         func()
     else:
         raise HamError('tried %d times, giving up now" % n)

try_repeatedly(5, do_the_thing)



-- 
Steven



More information about the Python-ideas mailing list