问题
Consider the following example:
class A:
def m():
pass
class B(A):
pass
And the following terminal output:
>>> b = B()
>>> b.m
<bound method A.m of <__main__.B object at 0x000001EFFF24C748>>
>>> super(b.__class__, b).m
<bound method A.m of <__main__.B object at 0x000001EFFF24C748>>
>>> b.m is super(b.__class__, b).m
False
>>> b.m == super(b.__class__, b).m
True
Why are they equal but not identical? Is a copy of the method made when it is inherited?
Are there better ways to test whether a child class has overridden a parent method?
回答1:
You can use the __dict__ attribute to check which methods and attributes have been overridden:
>>> class A:
... def m():
... pass
...
>>> class B(A):
... pass
...
>>> class C(A):
... def m():
... pass
...
>>> 'm' in A.__dict__
True
>>> 'm' in B.__dict__
False # not overridden
>>> 'm' in C.__dict__
True # overridden
回答2:
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
来源:https://stackoverflow.com/questions/62301590/can-we-use-super-to-test-identity-between-class-methods-in-the-mro