tags:

views:

45

answers:

2

This is what i want to do:

@MyDecorator
def f():
   pass

for d in f.decorators:
   print d
+3  A: 

This is not generally possible without the cooperation of the decorators. For example,

def my_decorator(f):
     def wrapper(*args, **kwargs):
         return f(*args, **kwargs)
     wrapper.decorators = [wrapper]
     if hasattr(f, 'decorators'):
         wrapper.decorators.extend[f.decorators]
     return wrapper

Essentially, all the decorator does is wrap the function as usual and then put a decorators attribute on the wrapper function. It then checks the wrapped function for a similar list and propagates it upwards.

This is pretty useless though

What I think you want is

def my_decorator(f):
       def wrapper(args):
           return f(args)
      wrapper.decorated = f
      return wrapper

This will allow you to do stuff like

@my_other_decorator # another decorator following the same pattern
@my_decorator
def foo(args):
    print args

foo.decorated(args) # calls the function with the inner decorated function (my_decorator)
foo.decorated.decorated(args) # original function

You can actually abstract this pattern into a decorator

def reversable(decorator):
    def wrapper(func):
        ret = decorator(func) # manually apply the decorator
        ret.decorated = func # save the original function
        return ret
    return wrapper

Now when you are writing your decorator:

@reversable
def my_decorator(f):
    def wrapper(x):
        return f(x + 1)
    return wrapper
aaronasterling
holy shit! thanks aaron
Ash Kim
Note that Python 3.2's `functools.wraps` uses the name `__wrapped__` to point to the original function. I recommend using the same name, so code can stop diverging on this. (I need to start doing this, too; I've always used the name "func".) I'd recommend actually using `functools.wraps`, but that's not much of a solution until 3.2 is actually in wide use.
Glenn Maynard
+1  A: 

The @MyDecorator syntax is just shorthand for writing the following Python code:

def f():
  pass
f = MyDecorator(f)

Written in this form, you can see that the decorators applied to the function are not kept track of in any way. You could make your decorators remember when they're applied (Aaron's answer has a couple good ideas on how to do this), but you'd have to wrap all third-party decorators with your own.

Cameron
thanks cameron!
Ash Kim