[Python-ideas] Method chaining notation

Chris Angelico rosuav at gmail.com
Sat Feb 22 05:31:35 CET 2014


On Sat, Feb 22, 2014 at 12:13 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Sat, Feb 22, 2014 at 04:30:03AM +1100, Chris Angelico wrote:
>> So here's the proposal. Introduce a new operator to Python, just like
>> the dot operator but behaving differently when it returns a bound
>> method. We can possibly use ->, or maybe create a new operator that
>> currently makes no sense, like .. or .> or something. Its semantics
>> would be:
>>
>> 1) Look up the attribute following it on the object, exactly as per
>> the current . operator
>> 2) If the result is not a function, return it, exactly as per current.
>> 3) If it is a function, though, return a wrapper which, when called,
>> calls the inner function and then returns self.
>
> When you say "a function", do you actually mean a function? What about
> other callables, such as methods (instance, class or static) or types?
> How does this interact with the descriptor protocol?

Well, I mean anything that can become a bound method. At some point, a
lookup is done and it returns a function (in the normal case), but I
guess presumably any callable will do at that point. I'm looking at
hooking in at the point where it becomes bound.

A bound method is a function wrapper that provides a 'self' argument.
A chaining bound method would be a function wrapper that provides a
'self' argument, and then returns it.

> 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:

for spam in can if tasty:
   eat(spam)

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

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.

ChrisA


More information about the Python-ideas mailing list