[Python-ideas] Proposal for function expressions

Steven D'Aprano steve at pearwood.info
Wed Jul 15 02:10:40 CEST 2009


On Wed, 15 Jul 2009 02:56:38 am Chris Perkins wrote:

> For me, avoiding thinking of a name was never the primary motivation
> - putting things in the "right order" is. But I do believe that there
> are situations where the context that a block of code sits in tells
> far more about its purpose that a name ever could - in those
> circumstances, a forced function name can be useless at best, and
> distracting clutter at worst. For example:
>
> y = sorted(x, key=&) do(item):
>     name = item.split('-')[1]
>     return name.upper()
>
> I think that forcing that two-line block of code to have a name would
> serve no purpose - it's abundantly clear what it does. 

I'm afraid I'm with Paul Moore on this one -- it's not clear to me 
either.

The key=& seems like a mysterious Perlism -- what's the & operator doing 
in there? (Admittedly, it *might* be nice to be able to write things 
like reduce(&, alist) instead of reduce(operator.and_, alist). But 
that's another story.) "do(item):" confuses me, because it looks like 
the start of a do loop, but it isn't.

None of this is to say that I couldn't learn the proposed syntax, but in 
my opinion it doesn't mesh well with existing Python constructs.

Did I understand correctly that you prohibited using `if`, `while` and 
other block statements inside the do block? If so, then to my mind the 
proposal is useless -- it's neither an expression, like the body of 
lambda, nor a block, like the body of a function, but a freakish 
chimera.


> I also think 
> that the current state of affairs encourages poorer readability - I
> mean, admit it, today you would probably write that snippet like
> this:
>
> y = sorted(x, key=lambda item: item.split('-')[0].upper())
>
> which to me loses clarity both by being crammed into one line, and by
> not being able to create the local variable "name", which tells you
> quite a bit about why the the item is being chopped up the way it is.

If I were doing that operation more than once, I'd make a function:

def get_canonical_name(item):
    return item.split('-')[0].upper()

and I'd give it a docstring and doctests. The function 
get_canonical_name tells you *much* more about why the item is 
processed the way it is than a mere local variable "name".

You'll note that I wouldn't bother using a local -- this is short 
enough, and simple enough, that I don't need it. But if I only did it 
once, then I see nothing wrong with the lambda version. If you're 
worried about it being "crammed" into one line:

y = sorted(x,  # use the canonical name as the sort key
    key=lambda item: item.split('-')[0].upper()
    )

works for me.


> Seriously, I guess this is where we differ - I think that improved
> readability _is_ a sufficient goal unto itself.  The only question is
> whether other people (OK, one other person in particular) thinks it
> improves readability, and if so, then by how much.

Personally, the only time I've ever missed the ability to create 
multi-line lambdas was when I had a series of code blocks like this:

try:
    BLOCK
except exception, e:
    process_error(e)

where the BLOCK was different in each one, and I really wanted to factor 
out the common code into a function "process" and pass each BLOCK as an 
argument:

while condition:
    process(BLOCK1)
process(BLOCK2)
if something:
    process(BLOCK3)

sort of thing.

To my mind, multi-line lambdas are really only useful for the ability to 
factor out common code, not to avoid defining a function or spreading 
lambdas out over multiple lines.



-- 
Steven D'Aprano



More information about the Python-ideas mailing list