Interfaces and Behavioral Contracts
An interface states what an object must provide: operations, accepted inputs, results and failure behavior. Callers can depend on that contract rather than one concrete class.
The UML model shows this implementation as an abstract base class, with an italic required operation. Solid hollow-triangle arrows represent the subclasses’ inheritance from it.
An Explicit Contract
Python’s abc module provides ABC and the @abstractmethod decorator. A subclass must override unresolved abstract operations before it can be instantiated. The next section develops this mechanism.
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount):
passDefines PaymentMethod; no visible output.
class CreditCardPayment(PaymentMethod):
def pay(self, amount):
print(f"Charging ${amount} to credit card.")
class PayPalPayment(PaymentMethod):
def pay(self, amount):
print(f"Processing PayPal payment of ${amount}.")Defines CreditCardPayment, PayPalPayment; no visible output.
The implementations simulate payments by printing; neither contacts a payment service.
methods = [CreditCardPayment(), PayPalPayment()]
for m in methods:
m.pay(49.99)Output
Charging $49.99 to credit card.
Processing PayPal payment of $49.99.
Both classes accept pay(amount). An abstract declaration does not prove that their signatures or business rules are correct.
Duck Typing
Duck-typed code calls the required operation without first checking a concrete type. A missing method or incompatible signature fails at runtime.
The UML model shows the inheritance actually present in the code: PDFReport extends Exportable; Chart is independent. Both supply the operation the caller needs.
class Exportable:
def export(self):
pass # expected to be overriddenDefines Exportable; no visible output.
This placeholder does not enforce an abstract contract.
class PDFReport(Exportable):
def export(self):
print("Exporting report as PDF...")
class Chart:
def export(self):
print("Exporting chart image...")Defines PDFReport, Chart; no visible output.
items = [PDFReport(), Chart()]
for item in items:
item.export() # works as long as the method existsOutput
Exporting report as PDF...
Exporting chart image...
These export methods print messages only; they create no PDF or image files.
Try it: rename Chart’s export method. Predict which call fails, then restore the shared operation.
We will now examine abstract classes more closely to see how Python can require subclasses to provide specific operations.