Access class object in class body

this is a contrived example, but only because I’m tring to semplify it…
Is there a way for a function invoked in a class body to access the class itself?
let me show you:


def my_deco(fun):
    ...
    return fun

class MyClass:
    @my_deco
    @classmethod
    def my_method(cls):
        ...

in this example I have my_deco that is invoked during the building of MyClass, and receive an instance of classmethod (that I’ve just discovered it’s a type!)

I want to collect fun and invoke it at a later time. The collection is easy, but I cannot invoke directly, because I have a reference to an “unbounded” classmethod instance. I can access fun.__wrapped__ to get to the (still unbounded) my_method, but I need to pass MyClass to it to correctly invoke the function.

is there a way - during the invocation of my_deco (such as in it’s body) to have access to the class where it has been called? I though of checking the stacktrace but I’m not sure about it.

I’ve also tried to poke at the fun attributes but it doesn’t seems to me that classmethod offers any reference to the class “parent” of the decorated method.

What should happen if it wasn’t invoked from within a class?

Are you sure you don’t just want a staticmethod instead?

As a general answer: No, because the class doesn’t yet exists, it only gets created after the class body is finished. That doesn’t mean the situation you want to solve is unsolvable, but it’s tricky.

Let’s just say I will branch it in two cases inside my_deco implementation. I can add as much ifs I want.

Unfortunately I don’t choose that part. I can only update my_deco implementation to detect the various cases. At the moment I need to just support classmethod

in the classmethod instance I saw some references to the “name” of the class, so I think I can do some tricks with globals and such, but I was wondering if there was a better way.

At the end of the day if instead I call my_deco(MyClass.my_method) after the class definition I have access to the bounded method. I was just hoping for a way to “bind” it myself

You also can’t add a base class to the class that has a __init_subclass__ defined? That would be the easiest and earliest way to collect such functions while having the class object available. Another pretty simple solution would be a decorator on the class.

Oh, that reminds me, you can potentially bind yourself with __set_name__, which should be called at a correct point in time. This would mean my_deco should be a class and also forward __get__ to the underlying decorator (i.e. classmethod)

It seems a good idea, but I’ve just run a bunch of checks and it seems to me that

  1. __set_name__ is called after the class definition, as in “before” the invocation of the decorator
  2. moreover it doesn’t seems to be called if I’m “creating” a decorator, but only if I’m defining a variable… I should do something like

class MyClass:
    my_deco = MyDeco()

    @my_deco
    @classmethod
    def my_method(cls):
        ...

which works but it’s cumbersome to use and “backward” to implement (firs is called MyDeco.__call__(fun), then MyDeco.__set_name__(...))

I fear I would go to a base class with an __init_subclass__

You are misunderstanding what I meant:

class my_deco:
    def __init__(self, clsmethod):
        assert isinstance(clsmethod, classmethod)
        self.__wrapped__ = clsmethod

    def __get__(self, instance, owner):
        return self.__wrapped__.__get__(instance, owner)

    def __call__(self, *args, **kwargs):
        return self.__wrapped__(*args, **kwargs)

    def __set_name__(self, owner, name):
        print(owner, name, self.__wrapped__)
        # Here we now have both the class and the classmethod



class MyClass:
    @my_deco
    @classmethod
    def my_method(cls):
        ...

Strange, I swear I’ve tried to get __set_name__ called with a bare @my_deco invocation…
but yeah, your example works.
I’ll use it as a base for my needs.
thank you