0

I know that in Python, given a class ClassA, with

inspect.getmembers(ClassA, predicate=inspect.ismethod)

I can iterate over the different methods present in ClassA. Inherited methods are also gathered, which is convenient in my case. But what I would need is, given a particular method method1 of ClassA, to get the class from which ClassA inherited method1. It might be ClassA itself, or any of its parents/grandparents. I thought I could recursively traverse the __bases__ attribute, looking for the method1 attribute at each step. But maybe this functionality is already implemented somewhere. Is there another way?

zeycus
  • 860
  • 1
  • 8
  • 20

1 Answers1

4

Look through the MRO (Method Resolution Order), using inspect.getmro() (which works on both old and new-style classes):

def class_for_method(cls, method):
    return next((c for c in inspect.getmro(cls) 
                 if method.__func__ in vars(c).values()), None)

There is currently no stdlib method to do this search for you, no.

Demo:

>>> import inspect
>>> def class_for_method(cls, method):
...     return next((c for c in inspect.getmro(cls) 
...                  if method.__func__ in vars(c).values()), None)
... 
>>> class Base1(object):
...     def foo(self): pass
... 
>>> class Base2(object):
...     pass
... 
>>> class ClassA(Base1, Base2):
...     pass
... 
>>> class_for_method(ClassA, ClassA.foo)
<class '__main__.Base1'>

If no base class is found, the above expression returns None:

>>> class Bar:
...     def spam(): pass
... 
>>> class_for_method(ClassA, Bar.spam) is None
True
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • I tested it and it exactly what I needed. Did not know about `getmro`. Thanks! – zeycus Mar 06 '14 at 08:36
  • @zeycus: I've refined it a little to be more robust in the face of overridden methods; it'll only find the *exact* base class a method came from, even if you passed in a method that has been overridden by a later baseclass now. – Martijn Pieters Mar 06 '14 at 08:45
  • Thanks again, I'll use the improved version. These subtleties are way beyond my current OOP Python knowledge. – zeycus Mar 06 '14 at 09:03