0

I need to:

  • Receive a method as argument (directly from the class, without instance)
  • Create an instance
  • Execute said method from instance

The thing is, how can I reliably get the class out of the method? I've tried researching something in the inspect module, but because there is no instance, it thinks of the method as a function rather than a method.

Here's some example of what I'm trying to do:

def execute_method(method):
    cls = get_class_from_method(method)
    obj = cls()
    getattr(obj, method.__name__)()


def get_class_from_method(method):
    pass # how?


execute_method(HelloView.say_hello)
Hugo Mota
  • 11,200
  • 9
  • 42
  • 60

1 Answers1

4

A Python 2 method objects have a im_class attribute referencing the class of the instance they are bound to:

cls = method.im_class

For an unbound method, in Python 3, you'll be out of luck (the function is returned entirely unchanged, with no reference to the class). Python 2 returns an unbound method type with the im_class attribute still there:

>>> class Foo(object):
...     def bar(self): pass
...
>>> Foo.bar.im_class
<class '__main__.Foo'>

In Python 3, your options are far more limited and are error-prone. You could look at the __qualname__ attribute of the function, and deduce from that what the class might be bound to in the global namespace:

>>> class Foo:
...     def bar(self): pass
...
>>> Foo.bar
<function Foo.bar at 0x10e97b268>
>>> Foo.bar.__qualname__
'Foo.bar'
>>> Foo.bar.__qualname__.rpartition('.')[0]
'Foo'
>>> Foo.bar.__globals__.get(Foo.bar.__qualname__.rpartition('.')[0])
<class '__main__.Foo'>

However, if the class was created in a function (and is thus a local), or the class was replaced via a class decorator or simply renamed in the global namespace, the above trick at best won't work, at worst give you an entirely different object, and you can't know if this is the case.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • It's not a bound method. – Hugo Mota Jan 05 '16 at 14:15
  • @hugo_leonardo: updated to actually work, sorry about that. – Martijn Pieters Jan 05 '16 at 14:17
  • Oh. ok (: ~ I hope there is a way for python 3 though. – Hugo Mota Jan 05 '16 at 14:17
  • 2
    @hugo_leonardo: there isn't any. You could try to interpret the `__qualname__` attribute and poke about for the parent class in the same globals. But that's not guaranteed to work, as the class could have been created in a local namespace or have been wrapped in a class decorator or otherwise is no longer present as a global with that name. – Martijn Pieters Jan 05 '16 at 14:19
  • I guess you're right. Just found out this is a duplicate question: http://stackoverflow.com/questions/3589311/get-defining-class-of-unbound-method-object-in-python-3 – Hugo Mota Jan 05 '16 at 14:22