In object-oriented programming, it is often useful to define a set of methods that a class should implement, without specifying how those methods should be implemented. This is known as an interface, and it allows you to create a contract that defines the expected behavior of a class. In Python, you can use abstract base classes (ABCs) to define interfaces and enforce the implementation of certain methods.
Abstract Base Classes:
An abstract base class is a class that defines a set of methods that a concrete (i.e., non-abstract) class must implement. In Python, you can define an abstract base class using the abc module and the @abstractmethod decorator.
For example, consider the following abstract base class Shape that defines an area method:
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
To create a concrete class that implements the Shape abstract base class, you must provide an implementation for the area method.
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
If you try to create an instance of the Shape abstract base class, you will get an TypeError because it is an abstract class and cannot be instantiated.
s = Shape() # TypeError: Can't instantiate abstract class Shape with abstract methods area
Instead, you should create an instance of a concrete class that implements the Shape abstract base class, such as Rectangle.
r = Rectangle(5, 7)
print(r.area()) # Output: 35
You can also define multiple abstract methods in an abstract base class. For example:
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
If a concrete class does not implement all of the abstract methods defined in the abstract base class, you will get a TypeError when you try to create an instance of that class.
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
r = Rectangle(5, 7) # TypeError: Can't instantiate abstract class Rectangle with abstract methods perimeter
Interfaces:
An interface is a set of methods that a class should implement, without specifying how those methods should be implemented. In Python, you can use abstract base classes to define interfaces, as described above.
To create a concrete class that implements the Shape interface, you must provide an implementation for the area method.
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
You can also define multiple methods in an interface. For example:
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
If a concrete class does not implement all of the methods defined in the interface, you will get a TypeError when you try to create an instance of that class.
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
r = Rectangle(5, 7) # TypeError: Can't instantiate abstract class Rectangle with abstract methods perimeter
You can also define multiple interfaces in a single abstract base class, using separate subclasses for each interface. For example:
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Polygon(Shape):
@abstractmethod
def perimeter(self):
pass
class Rectangle(Polygon):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
In this example, the Rectangle class implements both the Shape interface (by providing an implementation for the area method) and the Polygon interface (by providing an implementation for the perimeter method).
Exercises
To review these concepts, we will go through a series of exercises designed to test your understanding and apply what you have learned.
Write an abstract base class Shape that defines an area method, and a concrete class Rectangle that implements the Shape abstract base class. Test your implementation by creating a Rectangle object and printing its area.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
r = Rectangle(5, 7)
print(r.area()) # Output: 35
Write an abstract base class Shape that defines an area method and a perimeter method, and a concrete class Rectangle that implements the Shape abstract base class. Test your implementation by creating a Rectangle object and printing its area and perimeter.
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
r = Rectangle(5, 7)
print(r.area()) # Output: 35
print(r.perimeter()) # Output: 24
Write an abstract base class Shape that defines an area method and a perimeter method, and a concrete class Circle that implements the Shape abstract base class. Test your implementation by creating a Circle object with radius 5 and printing its area and perimeter.
from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius**2
def perimeter(self):
return 2 * math.pi * self.radius
c = Circle(5)
print(c.area()) # Output: 78.53981633974483
print(c.perimeter()) # Output: 31.41592653589793
Write an abstract base class Shape that defines an area method, a perimeter method, and a volume method. Create a concrete class Sphere that implements the Shape abstract base class, and test your implementation by creating a Sphere object with radius 5 and printing its area, perimeter, and volume.
from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
@abstractmethod
def volume(self):
pass
class Sphere(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 4 * math.pi * self.radius**2
def perimeter(self):
return 2 * math.pi * self.radius
def volume(self):
return (4/3) * math.pi * self.radius**3
s = Sphere(5)
print(s.area()) # Output: 314.1592653589793
print(s.perimeter()) # Output: 31.41592653589793
print(s.volume()) # Output: 523.5987755982989
Write an abstract base class Shape that defines an area method, a perimeter method, and a volume method. Create a concrete class Cylinder that implements the Shape abstract base class, and test your implementation by creating a Cylinder object with radius 5 and height 7 and printing its area, perimeter, and volume.
from abc import ABC, abstractmethod
import math
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
@abstractmethod
def volume(self):
pass
class Cylinder(Shape):
def __init__(self, radius, height):
self.radius = radius
self.height = height
def area(self):
return 2 * math.pi * self.radius * self.height + 2 * math.pi * self.radius**2
def perimeter(self):
return 2 * math.pi * self.radius
def volume(self):
return math.pi * self.radius**2 * self.height
c = Cylinder(5, 7)
print(c.area()) # Output: 471.2388980384689
print(c.perimeter()) # Output: 31.41592653589793
print(c.volume()) # Output: 523.5987755982989