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. -- https://mail.python.org/mailman/listinfo/python-list