Question

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?

Was it helpful?

Solution

This code will actually crash if you try running it. The problem is that in nested scopes like wrapped (and wrapper), you can read outer variables but not assign to them.

This is what the nonlocal keyword in 3.x is for (which would make delay increase across all "instances" of wrapped from a single call to retry). To replicate this in 2.x, you need to do something like delay_lst = [delay] and access it as delay_lst[0].

If you want the modifications to be local to wrapped, just make a new variable and initialize it with the value of delay.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top