[Python-ideas] Before and after the colon in funciton defs.

Sven Marnach sven at marnach.net
Mon Sep 19 15:22:18 CEST 2011

Nick Coghlan wrote:
> [...] allow a sequence of 'implicit locals' to be defined within
> square brackets after the parameter list.

I'm not quite sure whether the benefits of this proposal are worth the
further rococoization of the language.  As far as I can see, the only
benefit is keeping function signatures clean.

Looking at the use cases one by one:

> Micro-optimisation:
>     # Current Python (internal to functools.lru_cache with default
> argument hack)
>     def decorating_function(user_function, tuple=tuple, sorted=sorted,
> len=len, KeyError=KeyError):
>          ... # 60 line function
>     # Proposal - explicitly implicit locals to clarify real calling signature
>     def decorating_function(user_function) [tuple=tuple,
> sorted=sorted, len=len, KeyError=KeyError)]:
>          ... # 60 line function

The proposed syntax isn't explicit enough for my taste to justify the
change.  What the programmer really wants to tell the compiler is:
Bind the given names at compile time rather than at run time.  I'd
prefer if the syntax would reflect this intention, similar to the
"global" and "nonlocal" declarations:

    def decorating_function(user_function):
        earlybind tuple, sorted, len, KeyError

(Not being a native speaker of English, I don't even try to find a
less dull name for this than "earlybind".  And I'm quite aware that
the bar for the introduction of a new keyword is quite high.)

> Early binding in a loop:
>    # Current Python
>    adders = []
>    for i in range(10):
>       def f(x, _i=i):
>           return x + _i
>       adders.append(f)
>    # Proposal
>    adders = []
>    for i in range(10):
>       def f(x) [i=i]:  # Real calling signature is clear
>           return x + i
>       adders.append(f)

I don't see too much benefit of the proposed syntax for this use
case.  If f() is a local throw-away function, I wouldn't worry about
its signature.  If f() is a longer-lived object and I do care about
its signature, I'd uses a class:

    class Adder:
        def __init__(self, i):
            self.i = i
        def __call__(self, x):
            return x + self.i

    [...] adders.append(Adder(i))

I still think classes are the Python way to hide state, not closures.
That said, this case would also be covered by the "earlybind" porposal

> Algorithmic shared state (without a class):
>     # Current Python
>     def f(*, _cache=[]):
>         # Consenting adults, please don't override _cache when calling!
>     # Proposal
>     def f() [_cache=[]]:  # Real calling signature is clear
>         # _cache is an implicit local, not a keyword-only argument, so its safe

Again, I'd use a class to hide state in the first place.  If someone
really wants to avoid using a class for some reason, using function
attributes would also be a viable way:

    def f():
            cache = f._cache
        except AttributeError:
            cache = f._cache = []


More information about the Python-ideas mailing list