Skip to content

Instantly share code, notes, and snippets.

@kirsle kirsle/decorators.md
Created Sep 22, 2014

Embed
What would you like to do?
Python decorator order

What order does Python execute decorators in? It seems like this changed sometime between when they were first introduced (2.4) and now (2.7).

Given the code:

@foo
@bar
@baz
def myfunc():
    pass

Is the decorator calling order baz -> bar -> foo, or is it foo -> bar -> baz? It used to be from the bottom to the top (the decorator closest to your function def runs first), but now it seems to be run from top to bottom.

Or rather, is the code equivalent to foo(bar(baz(myfunc))) (bottom to top) or baz(bar(foo(myfunc))) (top to bottom)

Links that support one vs. the other:

Test script:

#!/usr/bin/env python

from functools import wraps

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        print "login_required called!"
        return f(*args, **kwargs)
    return decorated_function


def ajax_request(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        print "ajax_request called!"
        return f(*args, **kwargs)
    return decorated_function


@login_required
@ajax_request
def test1():
    print "Test 1, login above ajax"


@ajax_request
@login_required
def test2():
    print "Test 2, ajax above login"


test1()
print "=" * 80
test2()

Output (Python 2.7.5):

** login_required called!
** ajax_request called!
Test 1, login above ajax
================================================================================
** ajax_request called!
** login_required called!
Test 2, ajax above login
@Veedrac

This comment has been minimized.

Copy link

Veedrac commented Sep 23, 2014

@kirsle

This comment has been minimized.

Copy link
Owner Author

kirsle commented Dec 11, 2014

That issue implies that the decorators would execute from bottom to top, but my test script on Python 2.7.5 executed them from top to bottom.

@login_required
@ajax_request
def test1():
    print "Test 1, login above ajax"
** login_required called!
** ajax_request called!
Test 1, login above ajax

Unless there's something wrong with my test script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.