A builder pattern and decorators.
Yes, Python has decorators, but they're best used as "filters" that apply to functions or methods. Cache this, serialize the output of this function always, prepare this function to be used as a tool by an agentic harness. Not registration, not flow control. You may disagree but someone has to say it; FastAPI influenced the modern use of decorators far too much in the wrong direction.
Builder patterns are a Rust convention, because Rust has no named keyword arguments. A Python function already exposes a named contract. There is very little reason to ever to sequentially pass configuration parameters in chained method calls. If you need to add state that doesn't exist yet to a constructor or factory, that is not a builder pattern. That is registration. The one place where builder patterns should be tolerated is query builders. They iteratively build on a concept and having the additional "slot" for metadata (method name plus keyword arguments) is genuinely useful. Using methods which accept single parameter instead of keyword arguments is incorrect.
So decorators here specifically attach metadata to make a function a reusable component. Builder makes a workflow. In Hamilton it's all decorators because it's purely declarative construction (sans reusability, really).
Builder pattern isn't only used in Rust, but I agree it's hideous to use in Python.
Doesn't look any different than doing the same in C# or Java to me, it is kind of pointless in Python, the one thing the pattern gives you is building a class in such a way that you the developer know exactly what's what, so its really a developer ergonomics thing is how it looks like to me.
Fair point. I should have said "popularized in the modern software vernacular by Rust".
I think of Java immediately when I hear Builder Pattern, and I think anyone who has ever touched Java does as well.