I'm working on a decorator that will retry running a function up to N times as follows:
def retry(exceptions, truncate=5, delay=0.25):
"""Retry the decorated function using an exponential backoff strategy.
If the function does not complete successfully a TimeoutException is
raised."""
def wrapper(func):
@wraps(func)
def wrapped(*args, **kwargs):
tries = 0
while tries < truncate:
try:
return func(*args, **kwargs)
except exceptions, e:
print "%s, Retrying in %d seconds..." % (str(e), delay)
time.sleep(delay)
>> delay += delay
tries += 1
else:
raise TimeoutException()
return wrapped
return wrapper
To me the code looks sensible, but on the line highlighted pyflakes complains, reporting:
W804 local variable 'delay' (defined in enclosing scope on line x) referenced before assignment
This doesn't quite make sense to me. delay
has been assigned a value, and I presumably should be able to reference it as a I please. Can someone explain what the error is, and if reasonable, how I can fix it?
This code will actually crash if you try running it. The problem is that in nested scopes like
wrapped
(andwrapper
), you can read outer variables but not assign to them.This is what the
nonlocal
keyword in 3.x is for (which would makedelay
increase across all "instances" ofwrapped
from a single call toretry
). To replicate this in 2.x, you need to do something likedelay_lst = [delay]
and access it asdelay_lst[0]
.If you want the modifications to be local to
wrapped
, just make a new variable and initialize it with the value ofdelay
.