Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a decorator triggered every time a function is decorated, and not when the decorated function is called?

In the following piece of code, why is ls1 updated every time we decorate a function (e.g. when we decorate the function api4) but not every time we call the specific function?

ls1=[]

def register_usage(f):
    ls1.append((datetime.today(), f.__name__))
    return f

@register_usage
def api4():
    return 'api4'
like image 224
Vaggelis Ntaloukas Avatar asked Dec 12 '25 16:12

Vaggelis Ntaloukas


2 Answers

Because that's how decorators work.

When you write:

@register_usage
def api4():
  ...

That is exactly equivalent to:

def orig_api4():
  pass

api4 = register_usage(orig_api4)

That is, the decorator receives the decorated function as an argument and returns a new function, which from that point replaces the original function. This all happens at function definition time.

When you call the decorated function, you're just calling whatever function was returned by the decorator.

like image 79
larsks Avatar answered Dec 14 '25 05:12

larsks


To make a decorator that does some work every time the function is called, you need to create and return an inner function.

ls1=[]

def register_usage(f):
    def impl():
        ls1.append((datetime.today(), f.__name__))
        return f()
    return impl

@register_usage
def api4():
    return 'api4'

Now api4() will actually call impl(), which appends to your global list and then delegates to the original api4.

like image 35
Silvio Mayolo Avatar answered Dec 14 '25 04:12

Silvio Mayolo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!