lurscher
lurscher

Reputation: 26983

Closest thing to a virtual call in python

Python does not provide some built-in inheritance mechanism to call implementations of base virtual or abstract methods in the derived class from the base methods

I am wondering what is the closest thing in python that would provide the following structure:

class Base(?):
   def some_abstract_interface(self, **params):
     raise Unimplemented()
   def some_base_impl(self):
     self.some_abstract_interface(self, a=4, b=3, c=2)


class Derived(Base):

   @neat_override_decorator_here? 
   def some_abstract_interface(self, **params):
     print("actual logic here {0}".format(params))

d = Derived()
d.some_base_impl()
>>>output: actual logic here a=4, b=3, c=2

Upvotes: 1

Views: 77

Answers (2)

blhsing
blhsing

Reputation: 107005

You can already do that without any neat decorator:

class Base:
    def some_abstract_interface(self):
        raise NotImplemented

    def some_base_impl(self):
        self.some_abstract_interface()

class Derived(Base):
    def some_abstract_interface(self):
        print('actual logic here')

Derived().some_base_impl()

This outputs:

actual logic here

If you want to enforce that Base is an abstract class and cannot be used to instantiate an object directly, and that some_abstract_interface is meant to be an abstract method and always has to be overridden by an implementation of the method from a child class, you can make the base class inherit from the ABC class of the abc module and decorate abstract methods with abc.abstractmethod like this:

import abc

class Base(abc.ABC):
    @abc.abstractmethod
    def some_abstract_interface(self):
        raise NotImplemented

    def some_base_impl(self):
        self.some_abstract_interface()

class Derived(Base):
    def some_abstract_interface(self):
        print('actual logic here')

Derived().some_base_impl()

Upvotes: 6

chepner
chepner

Reputation: 532053

You simply make the call yourself. That's not going to be any heavier, syntactically, then the decorator you posit.

class Derived(Base):
    def some_abstract_interface(self, **params):
        self.some_base_impl()
        print('actual logic her {0}.format(params))

In fact, you don't even need to separate some_base_impl and some_abstract_interace; an abstract method can have an implementation but still require overriding.

from abc import ABC, abstractmethod


class Base(ABC):
    @abstractmethod
    def some_abstract_interface(self, **params):
        pass  # Put base implementation here


class Derived(Base):
    def some_abstract_interface(self, **params):
        super().some_abstract_interface(**params)
        print("actual logic here {0}".format(params))

Upvotes: 4

Related Questions