Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the containing class of a decorated method in Python

Tags:

python

I am trying to implement a decorator class which would decorate methods in other classes. However, I need the class which holds the decorated method available in the decorator. I can't seem to find it anywhere.

Here's an example:

class my_decorator(object):

  def __init__(self, arg1, arg2):
    print(self.__class__.__name__ + ".__init__")
    self.arg1 = arg1
    self.arg2 = arg2

  def __call__(self, my_callable):
    print(self.__class__.__name__ + ".__call__")
    print(type(my_callable))
    self.my_callable = my_callable
#    self.my_callable_method_class = ?where to get this?

    def function_wrapper(*args, **kwargs):
      print(self.__class__.__name__ + ".function_wrapper")
      print(self.arg1)
      self.my_callable.__call__(*args, **kwargs)
      print(self.arg2)

    return function_wrapper


class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):
    print(self.__class__.__name__ + ".decorated_method")
    print(type(self.decorated_method))
    print("hello")


m = MyClass()
m.decorated_method()

That will print out this:

my_decorator.__init__
my_decorator.__call__
<type 'function'>
my_decorator.function_wrapper
one
MyClass.decorated_method
<type 'instancemethod'>
hello
two

In the decorator class the callable is of type function, while inside the class itself it is of type instancemethod. I can get the im_class from instancemethod, but there is no such thing in function.

How can I get the class containing the decorated method from within the decorator?

I could do this:

class my_decorator(object):

  def __init__(self, cls, arg1, arg2):

.
.

class MyClass(object):

  @my_decorator(cls=MyClass, arg1="one", arg2="two")
  def decorated_method(self):

.
.

But I would not like to do that because it's redundant and not nice.

Or should I implement this some other way? I basicly need a couple of arguments to the decorator, and I need the class of the decorated method in the decorator.

like image 496
kortsi Avatar asked Nov 15 '12 08:11

kortsi


1 Answers

You could decorate the class:

@decorate
class MyClass(object):

  @my_decorator(arg1="one", arg2="two")
  def decorated_method(self):

and use the outer decorator to send the class argument to the inner.


None of your proposals can work, because they require access to the class before it exists. When you define a class, you first execute the code inside its body (defining functions etc) and then assign the resulting scope to the class as its __dict__. So at the time that decorated_method is defined, MyClass doesn't exist yet.

like image 99
Katriel Avatar answered Sep 21 '22 15:09

Katriel