Persistence of variable value within decorator function scope in python

Viewed 147

Listening to Reuven M. Lerner's PyCon 2019 talk on decorators, and came across the following example of a decorating function.

import time

def once_per_minute(func):
    """A decorator that prevents the decorated func 
    from being invoked more than once per minute"""

    last_invoked = 0

    def wrapper(*args, **kwargs):
        nonlocal last_invoked

        elapsed_time = time.time() - last_invoked

        if elapsed_time < 60:

            raise Exception(f"Only {elapsed_time} has passed")

        last_invoked = time.time()

        return func(*args, **kwargs)

    return wrapper

What caused confusion for me was, why does the last_invoked value persists with every run of the decorated function? I would assume that with every run of the decorated function, the decorator would be invoked. And every time the decorator is invoked, last_invoked should be reset to zero.

I looked into the documentation of the nonlocal keyword, and it seems to indicate that this is a variable that is bound in the nearest enclosing scope. That still does not explain why last_invoked is able to successfully track elapsed time.

0 Answers
Related