In Java, for example, the @Override annotation not only provides compile-time checking of an override but makes for excellent self-documenting code.

I'm just looking for documentation (although if it's an indicator to some checker like pylint, that's a bonus). I can add a comment or docstring somewhere, but what is the idiomatic way to indicate an override in Python?

4

12 Answers

Based on this and fwc:s answer I created a pip installable package

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!!!!!!! 
12

Here's an implementation that doesn't require specification of the interface_class name.

import inspect import re def 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 
5

If you want this for documentation purposes only, you can define your own override decorator:

def override(f): return f class 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?

4

Improvising on @mkorpela great answer, here is a version with

more precise checks, naming, and raised Error objects

def overrides(interface_class): """ Function override annotation. Corollary to @abc.abstractmethod where the override is not of an abstractmethod. Modified from answer """ def confirm_override(method): if method.__name__ not in dir(interface_class): raise NotImplementedError('function "%s" is an @override but that' ' function is not implemented in base' ' class %s' % (method.__name__, interface_class) ) def func(): pass attr = getattr(interface_class, method.__name__) if type(attr) is not type(func): raise NotImplementedError('function "%s" is an @override' ' but that is implemented as type %s' ' in base class %s, expected implemented' ' type %s' % (method.__name__, type(attr), interface_class, type(func)) ) return method return confirm_override 


Here is what it looks like in practice:

NotImplementedError "not implemented in base class"

class A(object): # ERROR: `a` is not a implemented! pass class B(A): @overrides(A) def a(self): pass 

results in more descriptive NotImplementedError error

function "a" is an @override but that function is not implemented in base class <class '__main__.A'> 

full stack

Traceback (most recent call last): … File "C:/Users/user1/project.py", line 135, in <module> class B(A): File "C:/Users/user1/project.py", line 136, in B @overrides(A) File "C:/Users/user1/project.py", line 110, in confirm_override interface_class) NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'> 


NotImplementedError "expected implemented type"

class A(object): # ERROR: `a` is not a function! a = '' class B(A): @overrides(A) def a(self): pass 

results in more descriptive NotImplementedError error

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'> 

full stack

Traceback (most recent call last): … File "C:/Users/user1/project.py", line 135, in <module> class B(A): File "C:/Users/user1/project.py", line 136, in B @overrides(A) File "C:/Users/user1/project.py", line 125, in confirm_override type(func)) NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'> 




The great thing about @mkorpela answer is the check happens during some initialization phase. The check does not need to be "run". Referring to the prior examples, class B is never initialized (B()) yet the NotImplementedError will still raise. This means overrides errors are caught sooner.

3

Python ain't Java. There's of course no such thing really as compile-time checking.

I think a comment in the docstring is plenty. This allows any user of your method to type help(obj.method) and see that the method is an override.

You can also explicitly extend an interface with class Foo(Interface), which will allow users to type help(Interface.method) to get an idea about the functionality your method is intended to provide.

4

Like others have said unlike Java there is not @Overide tag however above you can create your own using decorators however I would suggest using the getattrib() global method instead of using the internal dict so you get something like the following:

def Override(superClass): def method(func) getattr(superClass,method.__name__) return method 

If you wanted to you could catch getattr() in your own try catch raise your own error but I think getattr method is better in this case.

Also this catches all items bound to a class including class methods and vairables

Based on @mkorpela's great answer, I've written a similar package (ipromise pypi github) that does many more checks:

Suppose A inherits from B and C, B inherits from C.

Module ipromise checks that:

  • If A.f overrides B.f, B.f must exist, and A must inherit from B. (This is the check from the overrides package).

  • You don't have the pattern A.f declares that it overrides B.f, which then declares that it overrides C.f. A should say that it overrides from C.f since B might decide to stop overriding this method, and that should not result in downstream updates.

  • You don't have the pattern A.f declares that it overrides C.f, but B.f does not declare its override.

  • You don't have the pattern A.f declares that it overrides C.f, but B.f declares that it overrides from some D.f.

It also has various features for marking and checking implementing an abstract method.

You can use protocols from PEP 544. With this method, the interface-implementation relation is declared only at the use site.

Assuming you already have an implementation (let's call it MyFoobar), you define an interface (a Protocol), which has the signatures of all the methods and fields of your implementation, let's call that IFoobar.

Then, at the use site, you declare the implementation instance binding to have the interface type e.g. myFoobar: IFoobar = MyFoobar(). Now, if you use a field/method that is missing in the interface, Mypy will complain at the use site (even if it would work at runtime!). If you failed to implement a method from the interface in the implementation, Mypy will also complain. Mypy won't complain if you implement something that doesn't exist in the interface. But that case is rare, since the interface definition is compact and easy to review. You wouldn't be able to actually use that code, since Mypy would complain.

Now, this won't cover cases where you have implementations both in the superclass and the implementing class, like some uses of ABC. But override is used in Java even with no implementation in the interface. This solution covers that case.

from typing import Protocol class A(Protocol): def b(self): ... def d(self): # we forgot to implement this in C ... class C: def b(self): return 0 bob: A = C() 

Type checking results in:

test.py:13: error: Incompatible types in assignment (expression has type "C", variable has type "A") test.py:13: note: 'C' is missing following 'A' protocol member: test.py:13: note: d Found 1 error in 1 file (checked 1 source file) 
4

Not only did the decorator I made check if the name of the overriding attribute in is any superclass of the class the attribute is in without having to specify a superclass, this decorator also check to ensure the overriding attribute must be the same type as the overridden attribute. Class Methods are treated like methods and Static Methods are treated like functions. This decorator works for callables, class methods, static methods, and properties.

For source code see:

This decorator only works for classes that are instances of override.OverridesMeta but if your class is an instance of a custom metaclass use the create_custom_overrides_meta function to create a metaclass that is compatible with the override decorator. For tests, run the override.__init__ module.

In Python 2.6+ and Python 3.2+ you can do it (Actually simulate it, Python doesn't support function overloading and child class automatically overrides parent's method). We can use Decorators for this. But first, note that Python's @decorators and Java's @Annotations are totally different things. The prior one is a wrapper with concrete code while later one is a flag to compiler.

For this, first do pip install multipledispatch

from multipledispatch import dispatch as Override # using alias 'Override' just to give you some feel :) class A: def foo(self): print('foo in A') # More methods here class B(A): @Override() def foo(self): print('foo in B') @Override(int) def foo(self,a): print('foo in B; arg =',a) @Override(str,float) def foo(self,a,b): print('foo in B; arg =',(a,b)) a=A() b=B() a.foo() b.foo() b.foo(4) b.foo('Wheee',3.14) 

output:

foo in A foo in B foo in B; arg = 4 foo in B; arg = ('Wheee', 3.14) 

Note that you must have to use decorator here with parenthesis

One thing to remember is that since Python doesn't have function overloading directly, so even if Class B don't inherit from Class A but needs all those foos than also you need to use @Override (though using alias 'Overload' will look better in that case)

as python 3.6 and above, the functionality provided by @override can be easily implemented using the descriptor protocol of python, namingly the set_name dunder method:

class override: def __init__(self, func): self._func = func update_wrapper(self, func) def __get__(self, obj, obj_type): if obj is None: return self return self._func def __set_name__(self, obj_type, name): self.validate_override(obj_type, name) def validate_override(self, obj_type, name): for parent in obj_type.__bases__: func = parent.__dict__.get(name, None) if callable(func): return else: raise NotImplementedError(f"{obj_type.__name__} does not override {name}") 

Note that here set_name is called once the wrapped class is defined, and we can get the parent class of the wrapped class by calling its dunder method bases.

for each for its parent class, we would like to check if the wrapped function is implemented in the class by

  1. check that the function name is in the class dict
  2. it is a callable

Using i would be as simple as:

class AbstractShoppingCartService: def add_item(self, request: AddItemRequest) -> Cart: ... class ShoppingCartService(AbstractShoppingCartService): @override def add_item(self, request: AddItemRequest) -> Cart: ... 
1

Hear is simplest and working under Jython with Java classes:

class MyClass(SomeJavaClass): def __init__(self): setattr(self, "name_of_method_to_override", __method_override__) def __method_override__(self, some_args): some_thing_to_do() 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy