The Builder pattern separates the construction of a complex object from its final form. Instead of one constructor with many parameters you call small named steps and finish with build(). It is useful when an object has many optional parts, is assembled in several steps, or must be validated as a whole.
The telescoping constructor
To set the last optional parameter you must pass all earlier ones. The call Request("GET", "/users", None, {"page": 2}, None, 10, 3) is unreadable, and swapping 10 and 3 is not an error.
class Request:
def __init__(self, method, url, headers=None, params=None,
body=None, timeout=30, retries=0):
self.method, self.url = method, url
self.headers = headers or {}
self.params = params or {}
self.body = body
self.timeout, self.retries = timeout, retries
def __repr__(self):
return (f"{self.method} {self.url} params={self.params} "
f"timeout={self.timeout} retries={self.retries}")
print(Request("GET", "/users", None, {"page": 2}, None, 10, 3))GET /users params={'page': 2} timeout=10 retries=3Step-by-step construction with a fluent interface
Every step stores a part and returns self, so calls chain into a sentence. build() produces the product, here a SQL string with a tuple of parameters. Values travel as ? placeholders; they are never concatenated into the SQL.