Can a decorator of an instance method access the class? Can a decorator of an instance method access the class? python python

Can a decorator of an instance method access the class?


If you are using Python 2.6 or later you could use a class decorator, perhaps something like this (warning: untested code).

def class_decorator(cls):   for name, method in cls.__dict__.iteritems():        if hasattr(method, "use_class"):            # do something with the method and class            print name, cls   return clsdef method_decorator(view):    # mark the method as something that requires view's class    view.use_class = True    return view@class_decoratorclass ModelA(object):    @method_decorator    def a_method(self):        # do some stuff        pass

The method decorator marks the method as one that is of interest by adding a "use_class" attribute - functions and methods are also objects, so you can attach additional metadata to them.

After the class has been created the class decorator then goes through all the methods and does whatever is needed on the methods that have been marked.

If you want all the methods to be affected then you could leave out the method decorator and just use the class decorator.


Since python 3.6 you can use object.__set_name__ to accomplish this in a very simple way. The doc states that __set_name__ is "called at the time the owning class owner is created".Here is an example:

class class_decorator:    def __init__(self, fn):        self.fn = fn    def __set_name__(self, owner, name):        # do something with owner, i.e.        print(f"decorating {self.fn} and using {owner}")        self.fn.class_name = owner.__name__        # then replace ourself with the original method        setattr(owner, name, self.fn)

Notice that it gets called at class creation time:

>>> class A:...     @class_decorator...     def hello(self, x=42):...         return x...decorating <function A.hello at 0x7f9bedf66bf8> and using <class '__main__.A'>>>> A.hello<function __main__.A.hello(self, x=42)>>>> A.hello.class_name'A'>>> a = A()>>> a.hello()42

If you want to know more about how classes are created and in particular exactly when __set_name__ is called, you can refer to the documentation on "Creating the class object".


As others have pointed out, the class hasn't been created at the time the decorator is called. However, it's possible to annotate the function object with the decorator parameters, then re-decorate the function in the metaclass's __new__ method. You'll need to access the function's __dict__ attribute directly, as at least for me, func.foo = 1 resulted in an AttributeError.