[Python-ideas] several different needs [Explicit variable capture list]

Andrew Barnert abarnert at yahoo.com
Tue Jan 26 15:59:07 EST 2016


On Jan 26, 2016, at 11:40, Jim J. Jewett <jimjjewett at gmail.com> wrote:
> 
> (1)  Auxiliary variables
> 
>    def f(x, _len=len): ...
> 
> This is often a micro-optimization;

When _isn't_ it a micro-optimization? I think if it isn't, it's a very different case, e.g.:

    def len(iterable, _len=len):
        if something(iterable): special_case()
        else: return _len(iterable)

Obviously non-optimization use cases can't be solved by an optimizer. I think this is really more a special case of your #4, except that you're capturing a builtin instead of a nonlocal.

> But realistically, that _len isn't ugly *just* because it shouldn't be
> overridden; it is also inherently ugly.  I would prefer that something
> like Victor's FAT optimizer just make this idiom obsolete.

But, like most micro-optimizations, you should use this only when you really need it. Which means you probably can't count on a general-purpose optimizer that may do it for you, on some people's installations.

Also, marking that you're using an intentional micro-optimization is useful, even (or maybe especially) if it's ugly: it signals to any future maintainer that performance is particularly important here, and they should be careful with any changes.

Of course some people will abuse that (IIRC, a couple years ago, someone removed all the "register" declarations in the perl 5 source, which not only sped it up by a small amount, but also got people to look at some other micro-optimized code from 15 years ago that was actually pessimizing things on modern platforms...), but those people are the last ones who will stop micro-optimizing because you tell them the compiler can often do it better.

> (2)  immutable bindings
> 
> once X
> final Y
> const Z

But a default value neither guarantees immutability, nor signals such an intent. Parameters can be rebound or mutated just like any other variables.
> 
> So again, I think something like Victor's FAT optimizer (plus comments
> when immutability really is important) is a better long-term solution,
> but I'm not as sure as I was for case 1.

How could an optimizer enforce immutability, much less signal it? It only makes changes that are semantically transparent, and changing a mutable binding to immutable is definitely not transparent.

> (3)  Persistent storage
> 
>    def f(x, _cached_results={}): ...

> I still think it might be nice to just have a way of easily opening a
> new scope ...

You mean to open a new scope _outside_ the function definition, so it can capture the cache in a closure, without leaving it accessible from outside the scope? But then f won't be accessible either, unless you have some way to "return" the value to the parent scope. And a scope that returns something--that's just a function, isn't it?

Meanwhile, a C-style function-static variable isn't really the same thing. Statics are just globals with names nobody else can see. So, for a nested function (or a method) that had a "static cache", any copies of the function would all share the same cache, while one with a closure over a cache defined in a new scope (or a default parameter value, or a class instance) would get a new cache for each copy. So, if you give people an easier way to write statics, they'd still have to use something else when they want the other.


More information about the Python-ideas mailing list