Interfaces: Design Consistent Behaviors Across Classes

Introduction

In this chapter, you will learn how to model interface-style design in Python. Although Python does not have a separate interface keyword like some languages, you can still define clear behavior contracts using abstract base classes. This helps different classes follow the same rules while keeping implementations flexible.

Prerequisites

  • Python 3.10+ installed
  • Basic understanding of classes, inheritance, and abstract classes
  • Ability to run .py files in terminal or IDE

What Is an Interface (Conceptually)

An interface defines what a class must do, not how it does it.

Think of it like:

  • Power socket standard: devices must follow connector rules
  • Different device internals are allowed, as long as interface is respected

In Python, interface-like contracts are often implemented with:

  • ABC
  • @abstractmethod

1) Create an Interface-Style Contract

Use an abstract class to define required methods.

python
# Import interface tools
from abc import ABC, abstractmethod
 
 
# Interface-style base class
class Notifier(ABC):
    @abstractmethod
    def send(self, message):
        pass

Any concrete notifier class must implement send().

2) Implement the Interface in Multiple Classes

Different classes can implement the same contract differently.

python
# Import interface tools
from abc import ABC, abstractmethod
 
 
# Interface-style base class
class Notifier(ABC):
    @abstractmethod
    def send(self, message):
        pass
 
 
# Email implementation
class EmailNotifier(Notifier):
    def send(self, message):
        print(f"[Email] {message}")
 
 
# SMS implementation
class SMSNotifier(Notifier):
    def send(self, message):
        print(f"[SMS] {message}")
 
 
# Use implementations
email = EmailNotifier()
sms = SMSNotifier()
email.send("Welcome!")
sms.send("Verification code: 1234")

Same method name, different behavior.

3) Polymorphism with Interface Contract

You can treat all implementations uniformly.

python
# Collect different notifier objects
notifiers = [EmailNotifier(), SMSNotifier()]
 
# Polymorphic call
for notifier in notifiers:
    notifier.send("System maintenance at 8 PM.")

This is one of the biggest benefits of interface-oriented design.

Tip

Design Benefit

When new notifier types are added later (for example PushNotifier), existing calling code usually stays unchanged.

4) Optional Shared Logic in Interface-Style Base

You can include concrete helper methods in the abstract base class.

python
# Import interface tools
from abc import ABC, abstractmethod
 
 
# Interface-style base class
class PaymentProcessor(ABC):
    @abstractmethod
    def pay(self, amount):
        pass
 
    def validate_amount(self, amount):
        return amount > 0
 
 
# Concrete implementation
class WeChatPay(PaymentProcessor):
    def pay(self, amount):
        if self.validate_amount(amount):
            print(f"WeChat Pay success: {amount}")
        else:
            print("Invalid amount.")

This avoids repeating common validation logic in every child class.

5) Real Mini Example: Exporter Interface

This example creates a common export contract for multiple formats.

python
# Import interface tools
from abc import ABC, abstractmethod
 
 
# Exporter interface-style class
class DataExporter(ABC):
    @abstractmethod
    def export(self, data):
        pass
 
 
# CSV exporter
class CSVExporter(DataExporter):
    def export(self, data):
        print(f"Exporting to CSV: {data}")
 
 
# JSON exporter
class JSONExporter(DataExporter):
    def export(self, data):
        print(f"Exporting to JSON: {data}")
 
 
# Client code
def run_export(exporter, data):
    exporter.export(data)
 
 
# Test exporters
records = [{"name": "Emma", "score": 95}]
run_export(CSVExporter(), records)
run_export(JSONExporter(), records)

This pattern appears often in plugins, storage layers, and service adapters.

Warning

Do not confuse "duck typing" and "interface-style contract."
Duck typing is flexible and implicit; abstract contracts are explicit and stricter.

Common Beginner Mistakes

Mistake 1: Forgetting to Implement Required Methods

If an abstract method is missing in child class, instantiation fails.

Mistake 2: Using Interface-Style Design for Tiny One-Class Scripts

For very small scripts, this can add unnecessary complexity.

Mistake 3: Putting Too Much Business Logic in the Contract Class

Keep abstract base classes focused on shared contract and minimal shared helpers.

Surprise Practice Challenge

Build a "Login Strategy Interface":

  1. Create abstract class LoginProvider with login(username, password)
  2. Implement EmailLoginProvider
  3. Implement PhoneLoginProvider
  4. Put providers in a list and call login() on each
  5. Add one shared helper method in the base class (for example mask_username)

If you finish this, you are designing extensible architecture patterns used in production systems.

FAQ

Does Python have a real interface keyword?

No. Python usually models interfaces with abstract base classes and abstract methods.

When should I use interface-style design?

Use it when multiple classes should follow the same behavior contract.

Is duck typing enough in Python?

Sometimes yes, especially for small or dynamic code. For larger projects, explicit contracts can improve maintainability.

Can one class implement multiple interface-style contracts?

Yes. With multiple inheritance and careful design, a class can satisfy multiple contracts.