1

I'm having trouble actually following the source code, mostly because simply using grep on it isn't working.

Is there any way to find out from which class a certain method was inherited? For example, if there is class A, which has method foo() and bar(), and there is class B which has biz(), and class C which inherits all of it's attributes and methods from both A and B, how would I be able to determine which class foo() came from (without strictly looking at the source manually)?

Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
13steinj
  • 418
  • 5
  • 12
  • What text editor are you using? I would recommend using a proper IDE that hyperlinks you from a usage to a definition of a class – inspectorG4dget Oct 28 '15 at 04:17
  • I'm just using gedit; but I tried using Visual Studio on my Windows machine and it was still unable to find it. – 13steinj Oct 28 '15 at 04:37
  • I would recommend using PyCharm - you can get the pro version for free if you are a student. Otherwise, you could try eclipse with the pydev plugin. [Here's a list of python IDEs](http://stackoverflow.com/q/81584/198633) – inspectorG4dget Oct 28 '15 at 04:39
  • Or, look into [sublime text](http://www.sublimetext.com/3) with [Anaconda](http://damnwidget.github.io/anaconda/) for a more light-weight solution. – Dimitris Fasarakis Hilliard Oct 28 '15 at 04:57

2 Answers2

0

You can always access the super-classes of a class by looking in the __bases__ attribute for that class. Given three simple classes A, B, C (which for Py2.7 must inherit from object) :

class A: 
    def foo():
        pass
    def bar(): 
        pass    

class B:
    def biz(): pass

class C(A, B):
    pass

You can then iterate through the __bases__ for C and check whether an attribute, function foo (for example), exists in one of these classes.

To do this you can check for membership of foo in the __dict__ that holds the names for each class object in __bases__:

for base in C.__bases__: 
    if 'foo' in base.__dict__: 
        print("Attribute: '{}' defined in {}".format("foo", base))

Which prints:

Attribute: 'foo' defined in <class '__main__.A'>

For a more complete and general view:

# get all attributes of class C
vars = [classVar for classVar in dir(C) if not classVar.startswith('__')]

# iterate through all bases:
for base in C.__bases__: 
    for attr in vars:
        if attr in base.__dict__:
            print("Attribute: '{}' defined in {}".format(attr, base))

Which returns:

Attribute: 'bar' defined in <class '__main__.A'>
Attribute: 'foo' defined in <class '__main__.A'>
Attribute: 'biz' defined in <class '__main__.B'>

For all classes in the chain of inheritance you can switch __bases__ to __mro__ which indicates the method resolution order; a tuple of objects python searches when trying to resolve attribute references.

If we add a function to class C and make another class D that inherits from C:

class C(A, B): 
    def another(): pass

class D(C): pass

To get a view of where each function is defined, just switch __bases__ with __mro__ in the loop:

# hold D's attributes (functions names, variables.)
attrs = [var for var in dir(D) if not var.startswith('__')]
# vars contents: ['another', 'bar', 'biz', 'foo']

for base in D.__mro__: 
    for attr in attrs:    
        if attr in base.__dict__:
            print("Attribute: '{}' defined in {}".format(attr, base))

Now, this follows the mro tuple (equal to (__main__.D, __main__.C, __main__.A, __main__.B, object) in this specific case) and yields a similar output:

Attribute: 'another' defined in <class '__main__.C'>
Attribute: 'bar' defined in <class '__main__.A'>
Attribute: 'foo' defined in <class '__main__.A'>
Attribute: 'biz' defined in <class '__main__.B'>
Dimitris Fasarakis Hilliard
  • 150,925
  • 31
  • 268
  • 253
  • Would this work if say, the method is in a grandfather class? Great grandfather? Further up the tree? – 13steinj Oct 28 '15 at 04:37
  • @JonathanStein: You'd want to switch from `__bases__` (which only looks at the immediate parents) to `__mro__` for iteration (which contains the [C3 linearization of the inheritance chain](https://www.python.org/download/releases/2.3/mro/). – ShadowRanger Oct 28 '15 at 04:43
  • Yup, as @ShadowRanger said, change `__bases__` to `__mro__`. – Dimitris Fasarakis Hilliard Oct 28 '15 at 04:50
0

You can do checking through the parent classes as determined by the method resolution order and checking the members of each parent class:

for i in C.__mro__:
  if 'bar' in i.__dict__:
    print 'bar is in class ' + i.__name__

So, given the following classes definitions:

class A(object):
  def foo(self): pass
  def bar(self): pass

class B(object):
  def biz(self): pass

class C(A,B): pass

Running the above code will give

bar is in class A
MervS
  • 5,724
  • 3
  • 23
  • 37