46

I've been using abstract classes in Python with ABCMeta. When you write an abstract method you tag it with the decorator @abstractmethod. One thing that I found odd (and unlike other languages) is that when the subclass overrides the superclass method, no decorator like @override is provided. Does anyone know what the logic behind this might be?

This makes it slightly confusing for someone reading the code to quickly establish which methods override/implement abstract methods versus methods that only exist in the subclass.

Marco
  • 1,377
  • 15
  • 18
gnychis
  • 7,289
  • 18
  • 75
  • 113
  • 3
    Why would you need to provide a decorator? A decorator gives you the opportunity to replace a function with a new object, but there is no need for that in Python since it looks up names on a class dynamically (e.g. late binding), searching through the classes in Method Resolution Order (MRO) each time. Thus, a method defined in a subclass masks a method in a parent class *naturally*. – Martijn Pieters Dec 29 '15 at 23:56
  • And the *goal* of abstract methods is to ensure they are implemented; you can't create an instance of a class that has abstract methods still present. Not for them to be distinct from other methods. – Martijn Pieters Dec 29 '15 at 23:58
  • 5
    @MartijnPieters same behavior (MRO) is applied in Java. The `@Override` annotation is merely to help the developer catch typos during compilation-time (if the method name was misspelled, for example). – Nir Alfasi Dec 29 '15 at 23:58
  • @alfasin: `@abstractmethod` already gives you that; if you make a typo in the method that's supposed to be the concrete implementation, you'll get an error when creating an instance because the abstract method has no implementation. – Martijn Pieters Dec 30 '15 at 00:00
  • 3
    @MartijnPieters true, but `@abstractmethod` also forces the user to implement the method while `@Override` is optional. – Nir Alfasi Dec 30 '15 at 00:02
  • 3
    Someone proposed an implementation similar to what your looking for: http://stackoverflow.com/questions/1167617/in-python-how-do-i-indicate-im-overriding-a-method – Conchylicultor Feb 13 '17 at 21:48
  • Mypy supports the `typing.final` decorator to do this at type-check time rather than at import or run time. https://mypy.readthedocs.io/en/stable/final_attrs.html#final-methods – adzenith Feb 16 '21 at 01:42
  • 1
    Question should be reopened. `override` was added to `typing` by PEP 698 https://peps.python.org/pep-0698/. – Neil G Jun 01 '23 at 17:25

2 Answers2

21

The problem with trying to add @override is that at method definition time, the decorator has no way to tell whether or not the method actually overrides another method. It doesn't have access to the parent classes (or the current class, which doesn't even exist yet!).

If you want to add @override, the @override decorator can't actually do any override checking. You then have two options. Either there is no override checking, in which case @override is no better than a comment, or the type constructor needs to specifically know about @override and check it at class creation time. A convenience feature like @override really shouldn't need to complicate core parts of the type system implementation like that. Also, if you accidentally put @override on a non-method, the bug will go undetected until you try to call the decorated function and get a weird TypeError.

user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 1
    This is not true as of Python 3.6. – Neil G Aug 31 '17 at 05:42
  • @NeilG: Yeah, there's `__set_name__` now, so you could implement an `@override` decorator with actual functionality and only a few weird interactions (because it would have to return a custom type instead of an ordinary function). – user2357112 Aug 31 '17 at 06:00
  • 1
    I would do it by marking the methods using a decorator, and then doing your checks in `__init_subclass__`, which can be provided by a base class. – Neil G Aug 31 '17 at 06:02
  • @NeilG: If you're going to require a specific superclass, you could have already done the job in pre-3.6 with a metaclass (at the cost of conflicting with other metaclasses). – user2357112 Aug 31 '17 at 06:07
  • Yeah, that's true. This is by the way how `abstractmethod` works. – Neil G Aug 31 '17 at 06:09
  • 3
    @NeilG: Well, part of how `abstractmethod` works, because they also [baked some of the checks into `object.__new__`](https://github.com/python/cpython/blob/3.6/Objects/typeobject.c#L3503). I've always found it kind of weird how the design requires a specific metaclass and *still* puts some of the implementation somewhere as core as `object.__new__`. It seems like if they were going to put stuff in `object.__new__`, they might as well fold `ABCMeta`'s functionality directly into `type`. – user2357112 Aug 31 '17 at 06:18
  • Yes, I completely agree. That was my proposal [here](https://groups.google.com/forum/#!searchin/python-ideas/abstractmethod$20abc%7Csort:relevance/python-ideas/r2YLrIEQlig/MuHdIv2VAgAJ). If someone implements this without any performance penalty, then given that Guido gave his blessing it looks like such a change would make it into the language. – Neil G Aug 31 '17 at 06:19
  • 1
    @AntiEarth Nope. Feel free to post the idea on https://discuss.python.org/ As for the question, override was added to typing. – Neil G Jun 01 '23 at 17:23
14

You're confusing Python decorators with Java annotations. Despite the similar syntax, they are completely different things. A Java annotation is an instruction to the compiler. But a Python decorator is executable code that does something concrete: it wraps the function in another function which can change what it does. This is the case for abstractmethod just as much as any other decorator; it does something, namely tell the ABC that there is a method that needs overriding.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 3
    Mind you, if you really wanted the annotation for your own (dubious) readability benefit, it's trivial and cheap to do it. `def override(func): return func`. Done. Annotation available. Effectively free to apply it (at import time, you pay the trivial cost of calling the noop decorator function), have fun. – ShadowRanger Dec 30 '15 at 01:06
  • @ShadowRanger I failed to understand how does your suggestion implement the same `@Override` behavior as Java provides. – Nir Alfasi Dec 30 '15 at 02:27
  • @alfasin: It doesn't. It's just there as an cue to the programmer. It could be made to do more impressive stuff (though I suspect it would require metaclasses, since the decorator alone would apply before the method was attached to the class) like inspecting `__bases__` recursively to verify the presence of a method in the inheritance chain to assert something is actually being overridden, but if the primary goal is a sort of "in-language comment" to say "this overrides something else" in a standardized way for your code base, this does that. – ShadowRanger Dec 30 '15 at 02:34
  • 5
    @ShadowRanger `@Override` is not for documentation purpose alone (for that, you *could* add a code-comment after all...). It will fail the compilation if the annotated method is not *really* overriding a method in the base class. This is a safety-check. Adding an "id function" as a decorator will not provide such a safety check. – Nir Alfasi Dec 30 '15 at 03:46
  • 6
    This is nothing to do with Java - you can do this in C++ and C# as well at least. Thinking you are overriding a method on your parent class when you are in fact not doing so due to a spelling error or parameter mismatch (which can't happen in Python of course) is a nasty and silent mistake that any experienced programmer has made more than once. An `@overrides` annotation should cause a failure as early as possible to prevent you from silently making such a mistake. – Tom Swirly Jul 21 '17 at 10:33