Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Introspection to get decorator names on a method?

I am trying to figure out how to get the names of all decorators on a method. I can already get the method name and docstring, but cannot figure out how to get a list of decorators.

like image 588
Tony Avatar asked Jul 12 '10 20:07

Tony


People also ask

Can a decorator be a method?

Decorators can be implemented in a number of different ways. One useful use-case for decorators involves using them with methods defined in a class. Decorating methods in the classes we create can extend the functionality of the defined method.

What is decorator explain with example?

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

What is the correct syntax for using a decorator?

Decorators use a special syntax in JavaScript, whereby they are prefixed with an @ symbol and placed immediately before the code being decorated.

What are decorators in Python interview questions?

When we mention the word "decorator", what enters your mind? Well, likely something that adds beauty to an existing object. An example is when we hang a picture frame to a wall to enhance the room. Decorators in Python add some feature or functionality to an existing function without altering it.


2 Answers

I'm surprised that this question is so old and no one has taken the time to add the actual introspective way to do this, so here it is:

The code you want to inspect...

def template(func):     def wrapper(*args, **kwargs):         return func(*args, **kwargs)     return wrapper  baz = template che = template  class Foo(object):     @baz     @che     def bar(self):         pass 

Now you can inspect the above Foo class with something like this...

import ast import inspect  def get_decorators(cls):     target = cls     decorators = {}      def visit_FunctionDef(node):         decorators[node.name] = []         for n in node.decorator_list:             name = ''             if isinstance(n, ast.Call):                 name = n.func.attr if isinstance(n.func, ast.Attribute) else n.func.id             else:                 name = n.attr if isinstance(n, ast.Attribute) else n.id              decorators[node.name].append(name)      node_iter = ast.NodeVisitor()     node_iter.visit_FunctionDef = visit_FunctionDef     node_iter.visit(ast.parse(inspect.getsource(target)))     return decorators  print get_decorators(Foo) 

That should print something like this...

{'bar': ['baz', 'che']} 

or at least it did when I tested this with Python 2.7.9 real quick :)

like image 52
Jaymon Avatar answered Oct 09 '22 13:10

Jaymon


If you can change the way you call the decorators from

class Foo(object):     @many     @decorators     @here     def bar(self):         pass 

to

class Foo(object):     @register(many,decos,here)     def bar(self):         pass 

then you could register the decorators this way:

def register(*decorators):     def register_wrapper(func):         for deco in decorators[::-1]:             func=deco(func)         func._decorators=decorators                 return func     return register_wrapper 

For example:

def many(f):     def wrapper(*args,**kwds):         return f(*args,**kwds)     return wrapper  decos = here = many  class Foo(object):     @register(many,decos,here)     def bar(self):         pass  foo=Foo() 

Here we access the tuple of decorators:

print(foo.bar._decorators) # (<function many at 0xb76d9d14>, <function decos at 0xb76d9d4c>, <function here at 0xb76d9d84>) 

Here we print just the names of the decorators:

print([d.func_name for d in foo.bar._decorators]) # ['many', 'decos', 'here'] 
like image 32
unutbu Avatar answered Oct 09 '22 13:10

unutbu