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