views:

478

answers:

5

As an example,

def get_booking(f=None):
    print "Calling get_booking Decorator"
    def wrapper(request, **kwargs):
        booking = _get_booking_from_session(request)
        if booking == None:
            # we don't have a booking in our session.
            return HttpRedirect('/')
        else:
            return f(request=request, booking=booking, **kwargs)
    return wrapper

@get_booking
def do_stuff(request, booking):
    # do stuff here

The problem I am having is, the @get_booking decorator is being called even before I called the function that I am decorating.

Output on start:

Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
Calling get_booking Decorator
[26/Oct/2008 19:54:04] "GET /onlinebooking/?id=1,2 HTTP/1.1" 302 0
[26/Oct/2008 19:54:05] "GET /onlinebooking/ HTTP/1.1" 200 2300
[26/Oct/2008 19:54:05] "GET /site-media/css/style.css HTTP/1.1" 200 800
[26/Oct/2008 19:54:05] "GET /site-media/css/jquery-ui-themeroller.css HTTP/1.1" 200 25492

I haven't even made a call to a function that is decorated at this point.

I am just getting started with decorators, so maybe I am missing something. Any help?

+11  A: 

I believe python decorators are just syntactic sugar.

@foo
def bar ():
    pass

is the same thing as

def bar ():
    pass
bar = foo(bar)

As you can see, foo is being called even though bar has not been called. This is why you see the output from your decorator function. Your output should contain a single line for every function you applied your decorator to.

Dan
A: 

A decorator is called as soon as the decorated function is defined. It is equivalent to writing something like this:

def __do_stuff(...):
    ...

do_stuff = get_booking(__do_stuff)
David Schmitt
A: 

Thanks guys. I totally overlooked that. PythonFail on my part.

ashchristopher
A: 

python decorators are functions applied to a function to transform it:

@my_decorator
def function (): ...

is like doing this:

def function():...
function = my_decorator(function)

What you want to do is:

def get_booking(f=None):
    def wrapper(request, **kwargs):
        print "Calling get_booking Decorator"
        booking = _get_booking_from_session(request)
        if booking == None:
            # we don't have a booking in our session.
            return HttpRedirect('/')
        else:
            return f(request=request, booking=booking, **kwargs)
    return wrapper
Piotr Lesnicki
What good comes from giving a default value for the target function in a decorator?
muhuk
Especially since its never checked for None.
Dan
I don't really know what is his purpose, I thought it was rather for the redirection.
Piotr Lesnicki
+2  A: 

Since you are starting with decorators, I think reading these will be helpful, so that you know the pitfalls and workarounds beforehand.

Here are two links to earlier discussions on decorators.

http://stackoverflow.com/questions/306130/python-decorator-makes-function-forget-that-it-belongs-to-a-class#306277 http://stackoverflow.com/questions/308999/what-does-functoolswraps-do

Moreover the second link mentions 'functools' a module for higher-order functions, that act on or return other functions. Use of functools.wraps is advised since it preserves the doc string of the original function(decorated one).

Another issue was wrong method signatures while generating automatic docs for my project. but there is a workaround: http://stackoverflow.com/questions/147816/preserving-signatures-of-decorated-functions

Hope this helps.

JV