Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How much overhead do decorators add to Python function calls

Tags:

I've been playing around with a timing decorator for my pylons app to provide on the fly timing info for specific functions. I've done this by creating a decorator & simply attaching it to any function in the controller I want timed.

It's been pointed out however that decorators could add a fair amount of overhead to the call, and that they run 2-3x slower than an undecorated function.

Firstly, I would expect that executing a decorated function would take a smite longer than an undecorated one, but I would expect that overhead to be in the thousandths of seconds & be negligible compared to a SQL insert call. The decorator itself does simple simple timing calculations using time.time() & some very simple aggregation.

Do decorators add significant overhead to a system? I can't find anything to back that up.

like image 429
dochead Avatar asked Aug 23 '10 08:08

dochead


2 Answers

The overhead added by using a decorator should be just one extra function call.

The work being done by the decorator isn't part of the overhead as your alternative is to add the equivalent code to the decorated object.

So it's possible that the decorate function takes twice as long to run, but that's because the decorator is doing some important work that takes roughly the same time to fun as the undecorated function.

like image 133
John La Rooy Avatar answered Sep 18 '22 08:09

John La Rooy


What is important to know is that a decorator has a simple effect:

@decorator
def f():
    …

is just syntactic sugar for

def f():
    …
f = decorator(f)

Thus, if decorator does not do anything, you do not have any overhead when calling the decorated function (the call decorator(f) does take a little time, though), like in

decorator = lambda func: func
@decorator
def f():
    …

If the decorator does anything, you only get whatever time overhead the decorator involves. This typically include an additional function call (that of the decorated function), as in

def decorator(func):
    def decorated_func():
        print "Before calling function", func  # Some overhead (but that's normal)
        func()  # This will be a second function call, after the call to decorated_func()
    return decorated_func

Thus, in itself, decorating a function does not add much overhead for what you want to do: the only obvious overhead that you could in principle remove would be to not call func() in the decorated function but instead copy its full code, but the legibility of the code would suffer (legibility and flexibility are some of the reasons decorators do exist in the first place).

like image 30
Eric O Lebigot Avatar answered Sep 18 '22 08:09

Eric O Lebigot