[Python-ideas] Statement local functions and classes (aka PEP 3150 is dead, say 'Hi!' to PEP 403)

Steven D'Aprano steve at pearwood.info
Sun Oct 16 13:01:56 CEST 2011


Nick Coghlan wrote:

> The named function version fails because it gets things out of order:
> 
>     def sort_key(item):
>         return item.attr1, item.attr2
> 
>     sorted_list = sorted(original, key=sort_key)
> 
> That's more like pseudo code for "First, define a function that
> returns an object's attr1 and attr2 values. Than use that function to
> sort our list", a far cry from the originally requested operation.

I disagree strongly that the above "fails" in any sense, or that it is 
out of order at all. In English, one might say:

Given such-and-such a definition of sort_key, sorted_list is calculated 
from sorted(original, key=sort_key).

In my opinion, it is *much* more natural to state your premises (the 
givens) first, rather than after the conclusion. First you catch the 
rabbit, then you make it into stew, not the other way around.

Furthermore, by encouraging (or forcing) the developer to define 
sort_key ahead of time, it encourages the developer to treat it 
seriously, as a real function, and document it and test it.

If it's not tested, how do you know it does what you need?


[...]
> No, no, no - this focus on reusability is *exactly* the problem. It's
> why callback programming in Python sucks - we force people to treat
> one-shot functions as if they were reusable ones, *even when those
> functions aren't going to be reused in any other statement*.

That's not a bug, that's a feature.

If you're not testing your callback, how do you know they do what you 
expect? Because they're so trivial that you can just "see" that they're 
correct? In that case, we have lambda, we don't need any new syntax.


> That's the key realisation that I finally came to in understanding the
> appeal of multi-line lambdas (via Ruby's block syntax): functions
> actually have two purposes in life. The first is the way they're
> traditionally presented: as a way to structure algorithms into
> reusable chunks, so you don't have to repeat yourself. However, the
> second is to simply hand over a section of an algorithm to be executed
> by someone else. You don't *care* about reusability in those cases -
> you care about handing the code you're currently writing over to be
> executed by some other piece of code. Python only offers robust syntax
> for the first use case, which is always going to cause mental friction
> when you're only interested in the latter aspect.

You have missed at least two more critical purposes for functions:

- Documentation: both adding documentation to functions, and 
self-documenting via the function name. There's little mystery of what 
function sort_key is *supposed* to do (although the name is a bit light 
on the details), while:

     :sorted_lost = sorted(original, key=@)
     return item.attr1, item.attr2

is a magic incantation that is indecipherable unless you know the 
secret. (I realise that the above may not be your preferred or final 
suggested syntax.)

- And testing. If code isn't tested, you should assume it is buggy. In 
an ideal world, there should never be any such thing as code that's used 
once: it should always be used at least twice, once in the application 
and once in the test suite. I realise that in practice we often fall 
short of that ideal, but we don't need more syntax that *encourages* 
developers to fail to test non-trivial code blocks.



-- 
Steven



More information about the Python-ideas mailing list