[Python-ideas] Explicit variable capture list

Steven D'Aprano steve at pearwood.info
Wed Jan 20 19:10:32 EST 2016


On Tue, Jan 19, 2016 at 05:01:42PM -0800, Guido van Rossum wrote:
> On Tue, Jan 19, 2016 at 4:37 PM, Steven D'Aprano <steve at pearwood.info>
> wrote:
> 
> > On Tue, Jan 19, 2016 at 08:47:28AM -0800, Guido van Rossum wrote:
> >
> > > I think it's reasonable to divert this discussion to "value capture".
[...]
> > If I understand you correctly, that's precisely what a function default
> > argument does: capture the current value of the default value expression
> > at the time the function is called.
> 
> I think you misspoke here (I don't think you actually believe what you said
> :-).
> 
> Function defaults capture the current value at the time the function is
> *define*.

Oops! You got me. Yes, I meant defined, not called.


[...]
> > > The best syntax for such capture remains to be seen. ("Capture" seems to
> > > universally make people think of "variable capture" which is the opposite
> > > of what we want here.)
> >
> > If I recall correctly, there was a recent(?) proposal for a "static"
> > keyword with similar semantics:
> >
> > def func(a):
> >    static b = expression
> >    ...
> >
> > would guarantee that expression was evaluated exactly once.
> 
> Once per what? In the lifetime of the universe? Per CPython process start?
> Per call?
> 
> J/K, I think I know what you meant -- once per function definition (same as
> default values).

That's what I mean. Although, I am curious as to how we might implement 
the once per lifetime of the universe requirement :-)


> > If that
> > evaluation occurred when func was defined, rather than when it was first
> > called,
> 
> (FWIW, "when it was first called" would be a recipe for disaster and
> irreproducible results.)

It probably would be a bug magnet. Good thing I'm not asking for that 
behaviour then :-)


[...]
> > Scoping rules might be tricky to get right. Perhaps rather than a
> > declaration, "static" might be better treated as a block:
> >
> 
> Why? This does smell like a directive similar to global and nonlocal.

I'm just tossing the "static block" idea out for discussion, but if you 
want a justification here are two differences between capture/static 
and global/nonlocal which suggest they aren't that similar and so we 
shouldn't feel obliged to use the same syntax.

(1) global and nonlocal operate on *names*, not values. E.g. after 
"global x", x refers to a name in the global scope, not the local scope.

But "capture"/"static" doesn't affect the name, or the scope that x 
belongs to. x is still a local, it just gets pre-initialised to the 
value of x in the enclosing scope. That makes it more of a binding 
operation or assignment than a declaration.

(2) If we limit this to only capturing the same name, then we can only 
write (say) "static x", and that does look like a declaration. But maybe 
we want to allow the local name to differ from the global name:

    static x = y

or even arbitrary expressions on the right:

    static x = x + 1

Now that starts to look more like it should be in a block of code, 
especially if you have a lot of them:

    static x = x + 1
    static len = len
    static data = open("data.txt").read()

versus:

    static:
        x = x + 1
        len = len
        data = open("data.txt").read()


I acknowledge that this goes beyond what the OP asked for, and I think 
that YAGNI is a reasonable response to the static block idea. I'm not 
going to champion it any further unless there's a bunch of interest from 
others. (I'm saving my energy for Eiffel-like require/ensure blocks 
*wink*).



-- 
Steve


More information about the Python-ideas mailing list