Abstract Classes in Python

by: George El., April 2019, Reading time: 2 minutes

In my post Classes in Python I have an example of creating a class named Car and instantiating this class. In reality you would rarely do something like this, but rather use this class as a base class in order to create subclasses. Subclasses are classes that extend the base class and inherit all functionality from it. We can go one step further and define “Car” as an abstract class.

What is an abstract class? An abstract class is a class that defines some methods and properties, but ususally does not define any implementation. This has some consequences. First, you cannot instantiate this class. Second, subclasses, that is classes that inherit from this class, must provide implementation for all methods and properties defined in the abstract class with @abstractmethod decorator. Because python does not provide builtin functionality for abstract classes we have to import module abc (abstract base class).

from abc import ABC, abstractmethod 
class Car(ABC): 
    @abstractmethod
    def start(self): 
        pass

    @abstractmethod
    def stop(self): 
        pass

class VWCar(Car): 
  
    def start(self): 
        print("VW car started") 

    def stop(self): 
        print("VW car stopped") 
  
class ToyotaCar(Car): 
  
    def start(self): 
        print("Toyota car started") 
  
    def stop(self): 
        print("Toyota car stopped")

car1 = VWCar() 
car1.start() 
car1.stop() 
  
car2 = ToyotaCar()
car2.start()
car2.stop() 

the output is

VW car started
VW car stopped
Toyota car started
Toyota car stopped

Please note that I cannot instantiate Car class. If I try to do this, I will get an error. I will make my code more modular by splitting each class in its own file car.py

from abc import ABC, abstractmethod 

class Car(ABC):

    @abstractmethod
    def start(self): 
        pass

    @abstractmethod
    def stop(self): 
        pass

toyotacar.py

from .car import Car

class ToyotaCar(Car): 
  
    def start(self): 
        print("Toyota car started") 
  
    def stop(self): 
        print("Toyota car stopped")

vwcar.py

from .car import Car
 
class VWCar(Car): 
  
    def start(self): 
        print("VW car started") 

    def stop(self): 
        print("VW car stopped") 

nullcar.py

from .car import Car

class NullCar(Car):
    def __init__(self, carmodel):
        self.carmodel = carmodel

    def start(self):
        print("unknown car {}".format(self.carmodel))

    def stop(self):
        pass

main.py

from toyotacar import ToyotaCar
from vwcar import VWCar
from nullcar import NullCar

def getcar(carmodel):
    if carmodel == 'VW':
        return VWCar()
    elif carmodel == "Toyota":
        return ToyotaCar()
    else:
        return NullCar(carmodel)

for carmodel in ["VW","Toyota","Chevy"]:
    car = getcar(carmodel)
    car.start()
    car.stop()

this design in my my main.py with the elif statements is not good, because I have to modify it each time I create another car. In the next post we will use another class called carfactory which will create the instance of the car for us and make our code more maintainable.

comments powered by Disqus