S
Steven D'Aprano
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/
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/