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()
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.
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.
Python does not have the concept of virtual function or interface like C++.
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.
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:
>>> 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>
>>> 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>
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!')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With