Method chaining

Peter Otten __peter__ at web.de
Fri Nov 22 13:08:03 CET 2013


Steven D'Aprano wrote:

> A frequently missed feature is the ability to chain method calls:
> 
> x = []
> x.append(1).append(2).append(3).reverse().append(4)
> => x now equals [3, 2, 1, 4]
> 
> 
> This doesn't work with lists, as the methods return None rather than
> self. The class needs to be designed with method chaining in mind before
> it will work, and most Python classes follow the lead of built-ins like
> list and have mutator methods return None rather than self.
> 
> Here's a proof-of-concept recipe to adapt any object so that it can be
> used for chaining method calls:
> 
> 
> class chained:
>     def __init__(self, obj):
>         self.obj = obj
>     def __repr__(self):
>         return repr(self.obj)
>     def __getattr__(self, name):
>         obj = getattr(self.obj, name)
>         if callable(obj):
>             def selfie(*args, **kw):
>                 # Call the method just for side-effects, return self.
>                 _ = obj(*args, **kw)
>                 return self
>             return selfie
>         else:
>             return obj
> 
> 
> chained([]).append(1).append(2).append(3).reverse().append(4)
> => returns [3, 2, 1, 4]
> 
> 
> Tested, and works, in CPython 2.4 through 2.7, 3.2 and 3.3, Jython 2.5,
> and IronPython 2.6.
> 
> See here for further discussion of the limitations:
> 
> http://code.activestate.com/recipes/578770-method-chaining/

Here's my take:

class Chained(object):
    def __init__(self, value, method=None):
        self.value = value
        self.method = method
    def __call__(self, *args, **kw):
        result = self.method(*args, **kw)
        if result is None:
            result = self.value
        return Chained(result)
    def __getattr__(self, name):
        return Chained(self.value, getattr(self.value, name))

if __name__ == "__main__":
    print(Chained([]).append(1).append(2).append(3).reverse().append(4).value)
    print(Chained([]).append(1).extend([2,1,1]).count(1).value)

These things are nice to write as long as you omit the gory details, but 
personally I don't want to see the style it favours in my or other people's 
code.




More information about the Python-list mailing list