Using super(b.__class__, b)
produces an object that implements a __getattr__
method that will go up the __mro__
attribute starting at position 1 (skipping the current class) and look for the first class that has the specified attribute. It will then return that bound method. For a better explanation see this answer.
Knowing that all functions are also descriptors the following
class A:
def m(self):
pass
creates an object A
with the attribute m
which will be a function and descriptor. When you initialize an object a
of class A
, it will basically result in a.m = A.m.__get__(a)
which produces the bound method that has a
as the first argument self
.
Now since super
also retrieves bound methods what is being checked is the identity between 2 instances of A.m.__get__(a)
producing your terminal output:
>>> A.m.__get__(a)
<bound method A.m of <__main__.A object at 0x...>>
>>> A.m.__get__(a) is A.m.__get__(a)
False
So 2 calls to the class descriptor m
produce different bound instances and it is why the identity check fails. Instead you should test the identity of the functions that produced the bound methods. Luckily a bound method contains the __func__
attribute that returns the original function. So to lookup whether any instance's class has overridden an inherited function without knowing more than just the instance and name of the function you can do:
>>> a.__class__.m is super(a.__class__, a).m.__func__
True