Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I override a decorated method in Python?

Tags:

python

oop

Let's say I want to extend the following Python class, which includes a decorator that I don't know much about:

from somewhere import some_decorator

class One(object):
    @some_decorator
    def some_method(self):
        do_something()

Should I decorate the overridden method or not? In other words, can I safely do:

class Two(One):
    def some_method(self):
        super(Two, self).some_method()

Or do I need to do:

class Two(One):
    @some_decorator
    def some_method(self):
        super(Two, self).some_method()
like image 734
seddonym Avatar asked Dec 10 '15 16:12

seddonym


People also ask

Is there an override decorator in Python?

Runtime Override Checks in Python Today, there is an Overrides library that provides decorators @overrides (sic) and @final and will enforce them at runtime.

How do you override a method in Python?

In Python method overriding occurs by simply defining in the child class a method with the same name of a method in the parent class. When you define a method in the object you make this latter able to satisfy that method call, so the implementations of its ancestors do not come in play.

Is there @override in Python?

Overriding a method in the same class is not allowed. So, you need to do that in the child class by implementing the Inheritance concept. If you want to override the Parent Class method, create a function in the Child with the same name and number of parameters. This is called function overriding in Python.

What is a decorated function Python?

A decorator in Python is a function that takes another function as its argument, and returns yet another function . Decorators can be extremely useful as they allow the extension of an existing function, without any modification to the original function source code.


2 Answers

Remember what the @decorator syntax does:

@decorator
def foo():
    print "foo"

is just syntactic sugar for

def foo():
    print "foo"
foo = decorator(foo)

Thus, the undecorated function is no longer callable by its name after it has been decorated because its name has been assigned to something else.

This means that when you call super(Two, self).some_method() in the child class, then the decorated function some_method in the parent will be called.

Knowing whether or not you also need to decorate the child overridden method entirely depends on what you want to do and what the decorator does. But know that if you call super(Two, self).some_method(), then you will call the decorated function.

like image 167
Vincent Savard Avatar answered Oct 20 '22 21:10

Vincent Savard


For those wondering about edge cases, here is an example:

import functools


def print_hi(func):
    """Decorate a function to print stuff."""

    @functools.wraps(func)
    def wrapper_print_hi(*args, **kwargs):
        print(f"hello and up next: calling {func.__qualname__}")
        return func(*args, **kwargs)

    return wrapper_print_hi


class Foo:
    @print_hi
    def gets_overridden(self) -> None:
        print(f"Foo.gets_overridden")


class DFooNoRedecorate(Foo):
    def gets_overridden(self) -> None:
        """Overridden but didn't re-decorate."""
        print(f"{self.__class__.__name__}.gets_overridden")


class DFooRedecorate(Foo):
    @print_hi
    def gets_overridden(self) -> None:
        """Overridden and re-decorated."""
        print(f"{self.__class__.__name__}.gets_overridden")


class DFooNoRedecorateWithSuperCall(Foo):
    def gets_overridden(self) -> None:
        """Overridden but didn't re-decorate, with super call."""
        super().gets_overridden()
        print(f"{self.__class__.__name__}.gets_overridden")


class DFooRedecorateWithSuperCall(Foo):
    @print_hi
    def gets_overridden(self) -> None:
        """Overridden and re-decorated, with super call."""
        super().gets_overridden()
        print(f"{self.__class__.__name__}.gets_overridden")


if __name__ == "__main__":
    print("---")
    # Decorator doesn't happen when not explicitly called out in subclass
    DFooNoRedecorate().gets_overridden()
    print("---")
    # Decorator does happen when explicitly called out in subclass
    DFooRedecorate().gets_overridden()
    print("---")
    # Decorator happens during super call
    DFooNoRedecorateWithSuperCall().gets_overridden()
    print("---")
    # Decorator happens twice: from explicit call out and during super call
    DFooRedecorateWithSuperCall().gets_overridden()
    print("---")

Printed output:

---
DFooNoRedecorate.gets_overridden
---
hello and up next: calling DFooRedecorate.gets_overridden
DFooRedecorate.gets_overridden
---
hello and up next: calling Foo.gets_overridden
Foo.gets_overridden
DFooNoRedecorateWithSuperCall.gets_overridden
---
hello and up next: calling DFooRedecorateWithSuperCall.gets_overridden
hello and up next: calling Foo.gets_overridden
Foo.gets_overridden
DFooRedecorateWithSuperCall.gets_overridden
---
like image 37
Intrastellar Explorer Avatar answered Oct 20 '22 20:10

Intrastellar Explorer