Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Python pure virtual functions possible and/or worth it?

I may be coming from a different mindset, being primarily a C++ programmer. This question has to do with OOP in Python and more specifically pure virtual methods. So taking code I adapted from this question I am looking at this basic sample.

class Animal():
    def speak(self):
        print("...")

class Cat(Animal):
    def speak(self):
        print("meow")

class Dog(Animal):
    def speak(self):
        print("woof")

my_pets = [Dog(), Cat(), Dog()]

for _pet in my_pets:
     _pet.speak()

So you see it calls the speak function for different derived classes. Now my problem is that duck typing is all good and I think I have grasped it. However, is it wrong to pursue more strict OOP in Python? So I looked at the Abstract Base Classes and specifically abstractmethod. To me all this seems to do is allow me to call the base class method with super. Is there any way/reason(in Python) to make speak() pure such that implementing a derived animal without speak would throw an error?

My argument for such a pursuit would be when writing modules and frameworks that you intend people to subclass, this would self document for them the fact that they need implement the function. A probably very bad idea is something like this, having the base class "pure" function throw an exception. Problem is that this error is found at runtime!

class VirtualException(BaseException):
    def __init__(self, _type, _func):
        BaseException(self)

class Animal():
    def speak(self):
        raise VirtualException()

class Cat(Animal):
    def speak(self):
        print("meow")

class Dog(Animal):
    def speak(self):
        print("woof")

class Wildebeest(Animal):
    def function2(self):
        print("What!")

my_pets = [Dog(), Cat(), Dog(), Wildebeest()]

for _pet in my_pets:
    _pet.speak()
like image 687
benzeno Avatar asked Oct 20 '14 04:10

benzeno


People also ask

Why pure virtual functions are needed?

A pure virtual function is a virtual function in C++ for which we need not to write any function definition and only we have to declare it. It is declared by assigning 0 in the declaration. An abstract class is a class in C++ which have at least one pure virtual function.

What is pure virtual function in Python?

A pure virtual function is a member function of base class whose only declaration is provided in base class and should be defined in derived class otherwise derived class also becomes abstract. Classes having virtual functions are not abstract. Base class containing pure virtual function becomes abstract.

Are there virtual functions in Python?

Python does not have the concept of virtual function or interface like C++.

Do pure virtual functions have to be implemented?

As I've said, a pure virtual member function must always be implemented by every derived class intended to be concrete. But, it doesn't mean that you can't provide a default implementation for it in the abstract base class.


2 Answers

Abstract base classes already do what you want. abstractmethod has nothing to do with letting you call the method with super; you can do that anyway. Instead, any methods decorated with abstractmethod must be overridden for a subclass to be instantiable:

Python 3:

>>> class Foo(metaclass=abc.ABCMeta):
...     @abc.abstractmethod
...     def foo(self):
...         pass
...
>>> class Bar(Foo):
...     pass
...
>>> class Baz(Bar):
...     def foo(self):
...         return super(Baz, self).foo()
...
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods foo
>>> Bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Bar with abstract methods foo
>>> Baz()
<__main__.Baz object at 0x00000210D702E2B0>

Python 2:

>>> class Foo(object):
...     __metaclass__ = abc.ABCMeta
...     @abc.abstractmethod
...     def foo(self): pass
...
>>> class Bar(Foo): pass
...
>>> class Baz(Bar):
...     def foo(self): return super(Baz, self).foo()
...
>>> Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Foo with abstract methods foo
>>> Bar()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class Bar with abstract methods foo
>>> Baz()
<__main__.Baz object at 0x0000000001EC10B8>
like image 137
user2357112 supports Monica Avatar answered Oct 22 '22 02:10

user2357112 supports Monica


Problem is that this error is found at runtime!

Well, it is Python... most errors are going to show up at runtime.

As far as I know, the most common pattern to deal with is in Python is basically what you describe: just have the base class's speak method throw an exception:

class Animal():
    def speak(self):
        raise NotImplementedError('You need to define a speak method!')
like image 22
Marius Avatar answered Oct 22 '22 01:10

Marius