[Python-ideas] Proposal for Ruby-style anonymous block functions (that don't kill the indention)

Carl Johnson carl at carlsensei.com
Mon Nov 10 03:56:55 CET 2008


This list had a proposal last month to make everything an expression,  
and it has not infrequent attempts to create multi-line lambdas, and I  
think the reason for this is that people want a better way to create  
functions that act like Ruby-style blocks since sometimes it makes  
more sense to write the function that will be passed after the thing  
it will be passed to and not before. So, here's my proposal. I expect  
it to get rejected, but hey, someone approved @decorator, so maybe it  
will make it...

Instead of

 >>> def decorator(f):
...     def inner(*args, **kwargs):
...         print(*args, **kwargs)
...         return f(*args, **kwargs)
...     return inner
...

where the def inner comes before you know what it's going to be used  
for, why not

 >>> def decorator(f):
...     return @(*args, **kwargs):
...         print(*args, **kwargs)
...         return f(*args, **kwargs)
...

? Here's it's very straightforward that what you're doing is returning  
an anonymous function, and then you find out what's in the function.  
Similarly,

 >>> words = ["blah one", "Blah two", " bLAh three"]
 >>> sorted(words, key=@(word)):
...     word = word.lower()
...     word = word.replace("one", "1")
...     word = word.replace("two", "2")
...     word = word.replace("three", "3")
...     word = word.replace(" ", "")
...     return word
...
[u'blah one', u'Blah two', u' bLAh three']

Which will be equivalent to:

 >>> words = ["blah one", "Blah two", " bLAh three"]
 >>> def key(word):
...     word = word.lower()
...     word = word.replace("one", "1")
...     word = word.replace("two", "2")
...     word = word.replace("three", "3")
...     word = word.replace(" ", "")
...     return word
...
 >>> sorted(words, key=key)
[u'blah one', u'Blah two', u' bLAh three']

Again, I think it's clear here to be told first, "Oh, we're going to  
sort something" and then learn how the sorting will be done than it is  
to read a weird function and only after that learn what it's for.

Caveats: This shouldn't be allowed to work with two @s in one line. If  
you have two of them, you should give them names ahead of time with  
def. This also should not be allowed work inside a for-, if-, with-,  
or while- statement's initial expression, since the indenting won't  
work out. Also, myfunc = @(args) should be preemptively banned, since  
def is the one right way to do it. Also you shouldn't be allowed to do  
this to make one liners with this (as you can eg. with if-statements),  
since that's why there's lambda. And using this on the declaration  
line of a decorator is just crazy.

Of course, for all I know, Python's grammar is too simple to make this  
work with all the caveats, but if it's not, I think this might be a  
good way to improve readability without killing the indention-based  
nature of Python that we all know and love.

My other thought is that if @ is deemed to be too "Perl-ish" of line  
noise, def could be used as the keyword instead. Or perhaps a new  
keyword like "block" or something. That said, I think there is a good  
analogy here to the existing @-decorator where things are, strictly  
speaking, written out of order so that the readability is improved and  
the function that follows is given as an argument to the initial @ line.

Thoughts?

-- Carl



More information about the Python-ideas mailing list