I've implemented a retry decorator with some parameters:
def retry(max_tries: int = 3, delay_secs: float = 1, backoff: float = 1.5):
    print("level 1:", max_tries, delay_secs, backoff)
    def decorator(func):
        print("level 2:", max_tries, delay_secs, backoff)
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal delay_secs  ## UnboundLocalError if remove this line
            print("level 3:", max_tries, delay_secs, backoff)
            for attempt in range(max_tries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    print(f"attempt {attempt} Exception: {e}  Sleeping {delay_secs}")
                    time.sleep(delay_secs)
                    delay_secs *= backoff
            print("exceeded maximun tries")
            raise e
        return wrapper
    return decorator
@retry(max_tries=4, delay_secs=1, backoff=1.25)
def something():
    raise Exception("foo")
something()
If I remove this line, I got UnboundLocalError
nonlocal delay_secs
But that only happens for delay_secs, NOT for max_tries or backoff! I tried reordering/renaming the params and still that delay param is problematic.
Can you help me understand why that parameter out of scope within the wrapper function but the other 2 parameters are just fine?
Python: 3.9.2
OS: Debian 11 Linux
 
    