Search code examples
pythonpython-3.xintrospection

Getting class containing method


I'm writing a method decorator and require access to the class defining the method that is currently decorated.

The issue seems with this is, that with Python 3 methods in a class are just functions unless the class is instantiated.

Is there any way around this? I don't really want to fiddle around with __qualname__...

In [29]: class A:
   ....:     def B(self):
   ....:         pass
   ....:     

In [30]: A.B.__qualname__
Out[30]: 'A.B'

# This is what I want:
>>> get_class(A.B)
A

Solution

  • You can't, because at the time your decorator on a method is run, the class is yet to be created.

    An example illustrates this a little better:

    class Foo:
        @spam
        def bar(self): pass
    

    When spam(bar) is invoked to produce a decorated function, we are inside the pseudo-function that Python runs to define the class body. Only when that pseudo-function is done executing, is the local namespace of that function turned into the class body and the actual class object itself is created.

    That means that there is no Foo class object yet at the time spam() is run.

    Instead, create a class decorator:

    @spam
    class Foo:
        def bar(self): pass
    

    Now spam() is passed the whole, complete Foo class giving you access to both the class and the methods.

    If you need to mark specific methods on the class for decoration, you could use a marker decorator that sets attributes on the function:

    def marker(func):
        func._marked = True
        return func
    

    Use this decorator in the class body on methods that you want decorated, then use the class decorator to pick out those methods:

    @spam
    class Foo:
        @marker
        def bar(self): pass
    
        def baz(self): pass