Classes
Abstract Base Classes
ABC plus @abstractmethod declares the contract. Trying to construct the base class itself fails because at least one method has no implementation. A concrete describe() lives alongside the abstract area() so subclasses inherit shared behavior for free.
Source
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self) -> float:
...
def describe(self) -> str:
return f"shape with area {self.area()}"
try:
Shape()
except TypeError as error:
print(error)Output
Can't instantiate abstract class Shape without an implementation for abstract method 'area'A subclass that implements every abstract method is concrete and can be instantiated. It also inherits the non-abstract methods from the base class.
Source
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
print(Square(3).area())
print(Square(3).describe())Output
9
shape with area 9A subclass that forgets to implement an abstract method also cannot be instantiated — that is the value the ABC adds. The error fires at construction, not when something later tries to call the missing method.
Source
class Incomplete(Shape):
pass
try:
Incomplete()
except TypeError as error:
print(error)Output
Can't instantiate abstract class Incomplete without an implementation for abstract method 'area'Contrast with Protocol. A HasArea protocol accepts any class with an area() method, no inheritance required. Triangle does not inherit from Shape, so it satisfies the protocol but fails isinstance(_, Shape). Square satisfies both because it explicitly inherited from the ABC.
Source
from typing import Protocol
class HasArea(Protocol):
def area(self) -> float:
...
class Triangle:
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
def total_area(shapes: list[HasArea]) -> float:
return sum(shape.area() for shape in shapes)
print(total_area([Square(3), Triangle(4, 3)]))
print(isinstance(Triangle(4, 3), Shape))
print(isinstance(Square(3), Shape))Output
15.0
False
TrueNotes
ABCplus@abstractmethodblocks instantiation until every abstract method has an implementation.- ABCs are nominal — subclasses opt in by inheriting;
isinstance()reflects that opt-in. - Protocols are structural — any class with the right shape qualifies, regardless of inheritance.
- Prefer an ABC when shared implementation or explicit opt-in matters; prefer a Protocol when only behavior at the API boundary matters.
See also
- prerequisite: Protocols
- related: Inheritance and Super
- related: Classes
Run the complete example
Expected output
Can't instantiate abstract class Shape without an implementation for abstract method 'area'
9
shape with area 9
Can't instantiate abstract class Incomplete without an implementation for abstract method 'area'
15.0
False
True
Execution time appears here after you run the example.