Normally in Python, it is possible to detect whether a method has been overridden in a subclass using the following technique:
>>> class Foo:
... def mymethod(self): pass
...
>>> class Bar(Foo): pass
...
>>> Bar.mymethod is Foo.mymethod
True
The expression Bar.mymethod is Foo.mymethod
will evaluate to True
if the method from Foo
has not been overridden in Bar
, but will evaluate to False
if the method has been overridden in Bar
. This technique works well with dunder methods inherited from object
, as well as non-dunder methods:
>>> Bar.__new__ is Foo.__new__
True
>>> Bar.__eq__ is Foo.__eq__
True
We can formalise this logic in a function like so:
def method_has_been_overridden(superclass, subclass, method_name):
"""
Return `True` if the method with the name `method_name`
has been overridden in the subclass
or an intermediate class in the method resolution order
"""
if not issubclass(subclass, superclass):
raise ValueError(
"This function only makes sense if `subclass` is a subclass of `superclass`"
)
subclass_method = getattr(subclass, method_name)
if not callable(method):
raise ValueError(f"'{subclass.__name__}.{method_name}' is not a method")
return subclass_method is not getattr(superclass, method_name, object())
However, this technique fails when it comes to two methods: __init_subclass__
and __subclasshook__
:
>>> class Foo: pass
...
>>> class Bar(Foo): pass
...
>>> Bar.__init_subclass__ is Foo.__init_subclass__
False
>>> Bar.__subclasshook__ is Foo.__subclasshook__
False
And, for an even more perplexing example:
>>> type.__init_subclass__ is type.__init_subclass__
False
I have two questions:
__init_subclass__
or __subclasshook__
have been defined in a subclass after being left undefined in the superclass?__init_subclass__
is special-cased to be a class method, whether you decorate it with classmethod
or not. Just like Foo().mymethod
returns a new method
instance every time you access the attribute via a class instance, Foo.__init_subclass__
produces a new instance
method every time you access the attribute via the class itself.
__subclasshook__
, on the other hand, must be declared as a class method to work properly. It is not assumed to be a class method if you define it as a simple function/instance method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With