loading...

Fluent interface in python

mandrewcito profile image Andrés Baamonde Lozano ・1 min read

Intro

This is nothing new, Martin Fowler propose that way of expose apis several years ago. This is only a tiny explanation and the reasons because i choosen in certain cases this kind of implementation for my personal projects.

This past year i have been building a signalr core python client, i tried to build the public interface of the objects, as similiar as i can to the other official clients like javascript. That lead me to Fluent interface design. As a first aproximation i will code a toy example explaning the term.

Examples

class ExampleNonFluent(object):
    foo = None
    bar = None

Now if we want assing a value to foo and bar code will be as following:

my_class = ExampleNonFluent()
my_class = "new foo value"
my_class = "new bar value"

Changing the way of we implement our object with fluent interface will be similar to this:

class ExampleFluent(object):
    foo = None
    bar = None

    def cfg_foo(self, value):
        foo = value
        return self

    def cfg_bar(self, value):
        bar = value
        return self

Object implementation is more extense, yes but now building object will be more readable:

my_class = ExampleFluent()\
    .cfg_foo("new foo value")\
    .cfg_bar("new bar value")

What's your thoughts about this topic, place here your opinion, it can be a nice discussion :)

Discussion

markdown guide
 

In my opinion, fluent APIs are rarely needed in Python.
Optional keyword arguments in python allow, in a single function call, to specify a subset of required arguments.
For instance, one may argue that this interface is easier to use than fluent API:

ExampleNotFluent(foo="new foo value, bar="bar value",...)

ExampleNotFluent can be immutable, great!

Fluent APIs are more convenient in Java for instance, where keyword arguments are not a thing, and every single argument for every function must be specified. It is very common for builders in java to be fluent, where the user may only specify some arguments but not all.

User.builder().firstName("Spider").lastName("man").city(..).build()

Having said that, there is at least one instance where I really appreciate a fluent API in python: a chain of transformations where the intermediate objects are unwanted (and might cause confusion).
This is common in data manipulation and very useful in the Pandas library.
Here is a small snippet from a blog post about pandas I was too lazy to read:
gist.github.com/adiamaan92/740405b...