import warnings
OVERRIDE_FLAG = '_explicit_override'
def overrides(method):
setattr(method, OVERRIDE_FLAG, True)
return method
class OverrideGuard(type):
def __init__(cls, clsname, bases, methods):
super().__init__(clsname, bases, methods)
for method_name, method in methods.items():
if method_name.startswith('_'):
continue
first = None
for mro_cls in reversed(cls.__mro__):
if method_name in mro_cls.__dict__:
if not first:
first = mro_cls
else:
if not getattr(mro_cls.__dict__[method_name], OVERRIDE_FLAG, False):
warnings.warn(f"method '{method_name}' "
f"on class '{mro_cls.__name__}' "
f"implicitly overrides '{first.__name__}'")
class A(metaclass=OverrideGuard):
def double(self, x):
return 2*x
class B(A):
def double(self, x):
return 4*x
class C(A):
@overrides
def double(self, x):
return 4*x
.../site-packages/ipykernel/__main__.py:23: UserWarning: method 'double' on class 'B' implicitly overrides 'A'
%%timeit -p1 test = A()
sum(test.double(x) for x in range(10000))
100 loops, best of 3: 3 ms per loop
%%timeit -p1 test = B()
sum(test.double(x) for x in range(10000))
100 loops, best of 3: 3 ms per loop
%%timeit -p1 test = C()
sum(test.double(x) for x in range(10000))
100 loops, best of 3: 3 ms per loop