In Python, how do I indicate I'm overriding a method?
Based on this and fwc:s answer I created a pip installable package https://github.com/mkorpela/overrides
From time to time I end up here looking at this question.Mainly this happens after (again) seeing the same bug in our code base: Someone has forgotten some "interface" implementing class while renaming a method in the "interface"..
Well Python ain't Java but Python has power -- and explicit is better than implicit -- and there are real concrete cases in the real world where this thing would have helped me.
So here is a sketch of overrides decorator. This will check that the class given as a parameter has the same method (or something) name as the method being decorated.
If you can think of a better solution please post it here!
def overrides(interface_class): def overrider(method): assert(method.__name__ in dir(interface_class)) return method return overrider
It works as follows:
class MySuperInterface(object): def my_method(self): print 'hello world!'class ConcreteImplementer(MySuperInterface): @overrides(MySuperInterface) def my_method(self): print 'hello kitty!'
and if you do a faulty version it will raise an assertion error during class loading:
class ConcreteFaultyImplementer(MySuperInterface): @overrides(MySuperInterface) def your_method(self): print 'bye bye!'>> AssertionError!!!!!!!
Here's an implementation that doesn't require specification of the interface_class name.
import inspectimport redef overrides(method): # actually can't do this because a method is really just a function while inside a class def'n #assert(inspect.ismethod(method)) stack = inspect.stack() base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1) # handle multiple inheritance base_classes = [s.strip() for s in base_classes.split(',')] if not base_classes: raise ValueError('overrides decorator: unable to determine base class') # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n derived_class_locals = stack[2][0].f_locals # replace each class name in base_classes with the actual class type for i, base_class in enumerate(base_classes): if '.' not in base_class: base_classes[i] = derived_class_locals[base_class] else: components = base_class.split('.') # obj is either a module or a class obj = derived_class_locals[components[0]] for c in components[1:]: assert(inspect.ismodule(obj) or inspect.isclass(obj)) obj = getattr(obj, c) base_classes[i] = obj assert( any( hasattr(cls, method.__name__) for cls in base_classes ) ) return method
If you want this for documentation purposes only, you can define your own override decorator:
def override(f): return fclass MyClass (BaseClass): @override def method(self): pass
This is really nothing but eye-candy, unless you create override(f) in such a way that is actually checks for an override.
But then, this is Python, why write it like it was Java?