David Boshton
David Boshton

Reputation: 2765

What class is super(classname, instance) actually calling?

I've seen a bunch of the python method resolution order questions on Stack Overflow, many of which are excellently answered. I have one that does not quite fit.

When requesting super(MyClassName, self).method_name, I get a type that is not returned by the (single) parent class. Putting debug into the parent class shows that it isn't hit.

I would add some code snippets, but the codebase is massive. I have been into every class listed from MyClassName.__mro__ (which tells us what the method resolution order is) and NONE of them return the type I'm getting. So the question is...

What tool or attribute in Python can I use to find out what code is actually being called so that if this happens again I can easily find out what is actually being called? I ended up finding the solution, but I'd rather know how to tackle it in a less labour intensive manner.

Upvotes: 1

Views: 361

Answers (2)

Dunes
Dunes

Reputation: 40713

I think you might be getting confused between what a bound method is, and what the method resolution order is.

The returned method still counts as a bound method of the class of the actual object, even if function the method derives from is found on the parent class. This is because the method has been bound to an instance of the child class as opposed to the parent class.

eg.

class A:
    def f(self):
        return "A"
class B(A):
    def g(self):
        return super().f
class C(B):
    def f(self):
        return "C"

c = C()
method = c.g()
print(method) # prints <bound method C.f of <__main__.C object at 0x02D4FA10>>
print(method()) # prints A

In this instance, c.g() returns the function A.f bound to an instance of C.

To find the actual function that the bound method will call just examine the __func__ attribute:

assert method.__func__ is A.f 

Upvotes: 0

jonrsharpe
jonrsharpe

Reputation: 122052

You can use e.g. inspect.getmodule to, per its documentation:

Try to guess which module an object was defined in.

A simple example, with a.py:

class Parent(object):

    def method(self):
        return True

and b.py:

import inspect

from a import Parent

class Child(Parent):

    def method(self):
        parent_method = super(Child, self).method  # get the parent method
        print "inherited method defined in {}".format(
            inspect.getmodule(parent_method),  # and find out where it came from
        )
        return parent_method()


if __name__ == '__main__':
    Child().method()

Running b.py gives the result:

Parent defined in <module 'a' from 'C:/Python27\a.py'>

Upvotes: 1

Related Questions