[Python-ideas] Method chaining notation

Steven D'Aprano steve at pearwood.info
Sat Feb 22 06:16:27 CET 2014


On Sat, Feb 22, 2014 at 03:31:35PM +1100, Chris Angelico wrote:

> > Here's an alternative: add a `chained` wrapper to, oh, let's say
> > functools (I don't think it needs to be a built-in). In my hierarchy of
> > language preferredness, this suggests that while Python *supports*
> > method chaining, it isn't *preferred*. (If it were preferred, it would
> > happen by default, or there would be syntax for it.) If you want to
> > chain methods, you can, but it's a slightly unusual thing to do, and the
> > fact that you have to import a module and call a wrapper class should be
> > sufficient discouragement for casual (ab)use.
> 
> Downside of that is that it's really verbose. This sort of thing is
> useful only if it's short. It's like doing a filtered iteration:

It's not that long: chained() only adds nine characters, and 
if you're worried about that, call it chain() instead (seven). With your 
syntax, every dot lookup takes two chars instead of one, so it only 
takes eight method calls before my syntax is shorter than yours.

# unrealistically short method names just so the example fits on one line
obj->f()->g()->h()->i()->j()->k()->l()->m()
chain(obj).f().g().h().i().j().k().l().m()

In practice, I would expect that you would want to split the chain 
across multiple lines, just for readability, and if you're approaching a 
chain ten methods long, your code probably needs a rethink.

> 
> for spam in can if tasty:
>    eat(spam)
> 
> for spam in filter(lambda x: tasty, can):
>    eat(spam)

The number of characters isn't really relevent there. If that was 
written:

for spam in f(len, can):
    eat(spam)

which is shorter than "for spam in can if len(spam)", people would still 
want the filtered syntax. The problem is to think in terms of 
higher-order functions, and that doesn't come easily to most people.


> Using filter() is so verbose that there has been and will continue to
> be a stream of requests for a "filtered for loop" syntax. Having to
> pass everything through a named wrapper is too wordy to be useful.

Not so -- if the alternative is:

obj.f()
obj.g()
obj.h()
obj.i()
obj.j()
obj.k()
obj.l()
obj.m()

my version with chain() or chained() or even enable_chained_methods() 
wins hands down.

Given that Guido dislikes chaining methods, I don't think he'll want to 
make it too easy to chain methods :-)



-- 
Steven


More information about the Python-ideas mailing list