Python patterns for fun and profit: The Adapter Pattern — Code nomad
Introduction
Python patterns for fun and profit: The Adapter Pattern — Code nomad

Picture by Castorly Stock : https://www.pexels.com/nl-nl/foto/zwarte-muurpluggen-3639031/
Introduction
The Adapter pattern is used to make one interface compatible with another. It allows objects with different, and therefore incompatible interface to work together.
If you for example want to bring an existing class into your system with an interface that doesn’t match any existing interface, and you can not modify this class, you write an adapter class to bridge the gap.
It looks like this:

The pattern consists of different parts:
- The client has an object which implements the Subject interface.
- The object in question is the Adapter.
- The implementation of the operation() method in the Adapter wraps the concrete_operation in the RealSubject class.
That way we can talk to the RealSubject class using an already known interface. The Adapter class takes care of converting our method-calls for the RealSubject. Also, because this pattern is loosely coupled, changing the RealSubject should be relatively painless.
What is the difference between the Decorator and the Adapter pattern?
Purpose
Decorator: The decorator pattern is used to add behaviour to objects dynamically without modifying the source.
Adapter: Make one interface compatible with another
Use
Decorator: This pattern is used to when you want to add or extend behaviour to existing classes in a flexible and reusable way without creating a hierarchy of subclasses.
Adapter: Used to integrate an existing class with an interface which is not compatible with existing interfaces. Modifying this class is not needed if you wrap it in an Adapter.
Structure
Decorator: Creating a decorator pattern involves creating a set of decorator classes that implement the same interface as the component, thereby extending or modifying its behaviour
Adapter: Create an Adapter class, implementing the desired interface. This class also holds an instance of the class you want to adapted, the adaptee. The adapter delegates calls to the adaptee converting or transforming the input or output of these calls.
Example
Imagine having a bakery, you add things like GlazingDecorator or a WhippedCreamDecorator wrapping around your Pie-class to produces pies of the desired kind
Another classic example would be the conversion of units of measurement. If you have a classes which expects lengths to be in feet and inches, yet your client needs meters, you can wrap the classes in ConverterAdapter and have the conversion done automatically
Difference between Decorator and Adapter
In short, Adapter is used to make incompatible things work together, while the Decorator adds and extends functionality.
Implementation in Python
Preparing the stage
We will start by importing the following:
from abc import ABC, abstractmethod
Line by line:
- ABC stands for ‘Abstract Base Class’. When you derive from this class you simply tell Python that your class is meant to be abstract. This means that it is designed to be a template or a blueprint which should function as a baseclass, but should have no concrete implementation or instance of its own.
- The
@abstractmethoddecorator marks specific methods as abstract. This means that must and should be implemented by any concrete (i.e. non-abstract) subclass.
The target interface
We start by defining the interface of our target, that is the interface which our clients expect:
class Target(ABC):
@abstractmethod
def request(self) -> str:
pass
Line by line:
- The
Targetinterface derives fromABCso it is an abstract base class. - It defines one abstract method called
request().
The legacy service
To demonstrate the idea of an adapter, let’s define some LegacyService with a different interface:
class LegacyService:
def specific_request(self, data: str) -> str:
return f"LegacyService processing: {data}"
As you can see the interface of the LegacyService is different from our target.
The adapter
Since this interface is different, we need an adapter:
class ServiceAdapter(Target):
def __init__(self, legacy_service: LegacyService):
self._legacy_service = legacy_service
def request(self) -> str:
# Adapt the interface: convert Target.request() to LegacyService.specific_request()
return self._legacy_service.specific_request("adapted data")
Line by line:
- The
ServiceAdapterinherits from theTargetinterface, which means it must implement therequest()method. - The constructor receives an object of type
LegacyServiceas its argument. - The
request()method basically redirects a call torequest()to thespecific_request()method on theLegacyService
The client code
All we now need is a small function to call our request() method:
def client_code(target: Target):
return target.request()
Time to test
We can now test our adapter:
if __name__ == "__main__":
# Client can work with adapter as if it's a Target
legacy = LegacyService()
adapter = ServiceAdapter(legacy)
print(client_code(adapter))
What happens here is:
- We create our legacy service.
- We wrap it in our adapter,
- And call the desired functionality.
Conclusion
In conclusion, the Adapter pattern stands out as an indispensable tool in the object-oriented design toolkit, primarily serving as a vital bridge for resolving interface incompatibilities. Its function is elegantly simple yet profoundly impactful: enabling existing, potentially unmodifiable classes (the adaptee, or LegacyService in our example) to fulfill the contract of a client's expected interface (the Target).
The Python implementation effectively showcased the mechanics of this process, utilizing inheritance to conform to the Target and delegation to translate the method call for the LegacyService. This deliberate loose coupling is its greatest strength, promoting extensive code reuse and simplifying the integration of external dependencies or complex legacy systems without requiring disruptive internal modifications. The Adapter shields the client from the underlying complexity of the original service, resulting in code that is more stable and maintainable over time.
Furthermore, understanding the Adapter pattern is incomplete without clearly distinguishing it from the Decorator pattern. While the Decorator is dedicated to the dynamic addition or extension of responsibilities, the Adapter’s mission is purely one of transformation and interoperability. By encapsulating the conversion logic within a dedicated adapter class, we ensure that the client code remains clean and ignorant of the interface friction beneath it. This strategic isolation solidifies the Adapter pattern’s status as a cornerstone of flexible and resilient software architecture.
Originally published at https://codenomad.nl on October 6, 2025.
A message from our Founder
Hey, Sunil here. I wanted to take a moment to thank you for reading until the end and for being a part of this community.
Did you know that our team run these publications as a volunteer effort to over 3.5m monthly readers? We don’t receive any funding, we do this to support the community. ❤️
If you want to show some love, please take a moment to follow me on LinkedIn, TikTok, **Instagram. You can also subscribe to our [weekly newsletter](https://newsletter.plainenglish.io/)**.
And before you go, don’t forget to clap and follow the writer️!
메타데이터
- post_id
- cb627f17c3dc
- slug
- python-patterns-for-fun-and-profit-the-adapter-pattern-code-nomad-cb627f17c3dc
- url
- https://blog.stackademic.com/python-patterns-for-fun-and-profit-the-adapter-pattern-code-nomad-cb627f17c3dc
- canonical_url
- https://blog.stackademic.com/python-patterns-for-fun-and-profit-the-adapter-pattern-code-nomad-cb627f17c3dc
- author_url
- https://medium.com/@codenomadnl
- status
- ok
- fetched_at
- 2026-07-08 08:18:29