[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