Python decorators just syntactic sugar?

Question:

Possible Duplicate:
Understanding Python decorators

I am quite new on using Python decorators and from what I understand on my first impression that they are just syntactic sugar.

Is there a more profound use of them for more complex uses ?

Asked By: coredump

||

Answers:

I really like the decorator syntax because it makes code uber explicit

For example, in Django there’s this login_required decorator: https://docs.djangoproject.com/en/dev/topics/auth/#django.contrib.auth.decorators.login_required

To inject the @login_required behavior for a function/view, all you gotta do is attach the decorator to it (as opposed to putting if: … else: … control expressions everywhere etc. )

Read the PEP!

http://www.python.org/dev/peps/pep-0318/

it has losta history on the language decisions that were made, and why

Answered By: David Lam

Yes it is syntactic sugar. Everything can be achieved without them, but with a few more lines of code. But it helps you write more concise code.

Examples:

from functools import wraps

def requires_foo(func):
    @wraps(func)
    def wrapped(self, *args, **kwargs):
        if not hasattr(self, 'foo') or not self.foo is True:
            raise Exception('You must have foo and be True!!')
        return func(self, *args, **kwargs)
    return wrapped

def requires_bar(func):
    @wraps(func)
    def wrapped(self, *args, **kwargs):
        if not hasattr(self, 'bar') or not self.bar is True:
            raise Exception('You must have bar and be True!!')
        return func(self, *args, **kwargs)
    return wrapped

class FooBar(object):

    @requires_foo                 # Make sure the requirement is met.
    def do_something_to_foo(self):
        pass

We could also chain/stack the decorators on top of each other.

class FooBar(object):
    @requires_bar
    @requires_foo                 # You can chain as many decorators as you want
    def do_something_to_foo_and_bar(self):
        pass

OK, we could end up with lots and lots of decorators on top of each other.

I know! I’ll write a decorator that applies other decorators.

So we could do this:

def enforce(requirements):
    def wrapper(func):
        @wraps(func)
        def wrapped(self, *args, **kwargs):
            return func(self, *args, **kwargs)
        while requirements:
            func = requirements.pop()(func)
        return wrapped
    return wrapper

class FooBar(object):
    @enforce([reguires_foo, requires_bar])
    def do_something_to_foo_and_bar(self):
        pass

This is a small sample just to play with.

Answered By: rantanplan