How to Build a Fluent Interface with the Builder Pattern in Python
Learn to implement a fluent builder pattern in Python by chaining methods that return self, enabling readable object construction.
Python code
33 linesclass Pizza:
def __init__(self):
self.size = None
self.toppings = []
self.crust = None
def set_size(self, size):
self.size = size
return self
def add_topping(self, topping):
self.toppings.append(topping)
return self
def set_crust(self, crust):
self.crust = crust
return self
def build(self):
return self
def __str__(self):
return f"Pizza(size={self.size}, crust={self.crust}, toppings={self.toppings})"
if __name__ == "__main__":
pizza = (Pizza()
.set_size("large")
.add_topping("mushrooms")
.add_topping("olives")
.set_crust("thin")
.build())
print(pizza)
Output
Pizza(size=large, crust=thin, toppings=['mushrooms', 'olives'])
How it works
The Builder pattern separates object construction from its representation. Each setter method returns self, enabling method chaining and a fluent interface. This makes the code more readable and reduces the chance of passing wrong arguments to constructors. The build method returns the finalized object, which here is the same instance, but it can be extended to validate or create immutable copies. By returning self from each method, you create a consistent, chainable API that improves code flow and readability.
Common mistakes
- Forgetting to return `self` from setter methods, breaking the chain.
- Assuming `build` creates a new object; it returns the same instance, so mutations after build affect the original.
- Not initializing mutable attributes (like `toppings`) with a fresh list in `__init__`, causing shared state across instances.
Variations
- Use dataclasses and a separate builder class to enforce required fields and immutability.
- Implement a `copy()` method to return a clone of the builder at each step, preventing side effects.
Real-world use cases
- Building complex HTTP request objects with many optional headers and parameters in a readable chain.
- Configuring database connection settings step-by-step in a setup script with clear optional flags.
- Constructing nested report objects in a data pipeline, where each field is optional and defaults matter.
Sponsored
More from OOP & classes
- Add property getter setter validation in Python easy
- Binary Tree Inorder Traversal in Python easy
- Borg pattern shared state in Python medium
- Bridge Pattern in Python: Separate Abstraction from Implementation medium
- Composable Predicates with the &, |, ~ Operators in Python medium
- Composition over Inheritance: How to Build a Wallet Account in Python easy
Keep learning
Related tutorials and quizzes for this topic.