[Python-ideas] Multi-statement anonymous functions

musicdenotation at gmail.com musicdenotation at gmail.com
Mon Jan 13 12:06:00 CET 2014


Mutable namespaces and modules are just workarounds and cannot be substituted for local namespaces.


---Original message---
From: Andrew Barnert
Sent: Mon, 13 Jan 2014 00:21:07 -0800
To: <|musicdenotation at gmail.com|><|python-ideas at python.org|>
Subject: Re: [Python-ideas] Multi-statement anonymous functions


From: "musicdenotation at gmail.com" <musicdenotation at gmail.com>

Sent: Sunday, January 12, 2014 10:48 PM


> Subject: [Python-ideas] Multi-statement anonymous functions
> 
> Proposed syntaxes:
>>  let function(*args,**kwargs):
>>      ...body...
>>  function2(...args...):
>>      ...body...
>>  in:
>>      [statements]
> 
>>  do:
>>      [statements]
>>  where [function declarations in the same form as above]
> 
> Inspired by Haskell and Julia.
> 
> This has the advantage that declared functions aren't binded to names 
> outside their context.


I think there's something interesting here, but I'm not seeing it. What's the actual use case for this?

If you haven't read PEP 403 and PEP 3150, you should; they both offer similar (but not identical) features in a way that seems more readable (both more compact, and "fronting" the most important part of the construct):


    @in statement that uses function1
    def function1(*args, **kwargs):
        body

    statement that uses function1 and var1 given:
        def function1(*args, **kwargs):
            body
        var1 = value

Meanwhile, my first question for your syntax is: Why limit it to function definitions? It's worth noting that a Haskell let statement creates local bindings for any values you want; it's not restricted to functions. And that restriction is the only thing that forces the awkward block structure (which would need to be parsed differently than existing Python structures, both by the compiler and by human readers). Why not just a let statement that lets you execute _any_ statements in a local scope, then use that scope:

    let:

        def function1(*args, **kwargs):
            body
        var = value
        any other statement you want
    in:
        statements

… or, for that matter, just a local-scope statement:

    local:
        def function1(*args, **kwargs):
            body
        var = value
        any other statement you want
        statements that use those definitions


This has an advantage over Nick Coghlan's two proposals in that you get to run a full suite with the local scope, instead of just a single statement. (His fronting of the statement makes that restriction necessary; yours doesn't.)

But I'm wondering why you need a local scope. 

The let statement is necessary in Haskell because namespaces, like everything else, are immutable, and there are no real assignments; if you want to bind another variable, you have to create a new scope with that binding on top of the existing one. In Python, if you want to bind another variable, you just use an assignment/def/class/etc. And if you're worried about the name being accessible from outside of the namespace (e.g., if someone does a "from foo import *" on you), there are already idiomatic ways to deal with that: prefix the name with _, or give the module an __all__. Or, again: Python namespaces are mutable, so you can just del a binding after you're done with it if you really need to.

Coming at it from a different angle, JavaScript—which has mutable namespaces very much like Python—needs local scopes pretty frequently. But that's only because it has no modules, so everything is in one giant global namespace, which makes it hard to avoid conflicts, figure out where things are defined, etc. So that doesn't seem to apply to Python either.

Also, in most cases where you _do_ need a local scope, just defining and calling a function works just fine. That's what people do in Python when they need a local binding for micro-optimization purposes. And the same idiom is used all over the place in JavaScript (which, again, needs local scopes much more often than Python). Is there a use case where that isn't appropriate?


More information about the Python-ideas mailing list