[Python-ideas] Explicit variable capture list

Andrew Barnert abarnert at yahoo.com
Tue Jan 19 11:22:51 EST 2016


On Jan 19, 2016, at 06:10, haael at interia.pl wrote:
> 
> 
> Hi
> 
> C++ has a nice feature of explicit variable capture list for lambdas:
> 
>    int a = 1, b = 2, c = 3;
>    auto fun = [a, b, c](int x, int y){ return a + b + c + x + y};
> 
> This allows easy construction of closures. In Python to achieve that, you need to say:
> 
>    def make_closure(a, b, c):
>        def fun(x, y):
>            return a + b + c + x + y
>        return def
>    a = 1
>    b = 2
>    c = 3
>    fun = make_closure(a, b, c)
> 
> My proposal: create a special variable qualifier (like global and nonlocal) to automatically capture variables
> 
>    a = 1
>    b = 2
>    c = 3
>    def fun(x, y):
>        capture a, b, c
>        return a + b + c + x + y
> 
> This will have an effect that symbols a, b and c in the body of the function have values as they had at the moment of function creation. The variables a, b, c must be defined at the time of function creation. If they are not, an error is thrown. The 'capture' qualifier may be combined with keywords global and nonlocal to change lookup behaviour.

What you're suggesting is the exact opposite of what you say you're suggesting. Capturing a, b, and c in a closure is what Python already does. What you're trying to do is _not_ capture them and _not_ create a closure. So calling the statement "capture" is very misleading, and saying it "allows easy construction of closures" even more so.

In C++ terms, this:

    def fun(x, y): return a + b + c + x + y

means:

    auto fun = [&](int x, int y) { return a + b + c + x + y; };

It obviously doesn't mean this, as you imply:

    auto fun = [](int x, int y) { return a + b + c + x + y; };

... because that just gives you a compile-time error saying that local variables a, b, and c aren't defined, which is not what Python does.

If you're looking for a way to copy references to the values, instead of capturing the variables, you write this:

    def fun(x, y, a=a, b=b, c=c): return a + b + c + x + y

And if you want to actually copy the values themselves, you have to do that explicitly (which has no visible effect for ints, of course, but think about lists or dicts here):

    def fun(x, y, a=copy.copy(a), b=copy.copy(b), c=copy.copy(c)): return a + b + c + x + y

... because Python, unlike C++, never automatically copies values. (Again, think about lists or dicts. If passing them to a function or storing them in a variable made an automatic copy, as in C++, you'd be wasting lots of time and space copying them all over the place. That's why you have to explicitly create vector<int>& variables, or shared_ptr<vector<int>>, or pass around iterators instead of the container itself--because you almost never actually want to waste time and space making a copy if you're not mutating, and you almost always want the changes to be effective if you are mutating.)


More information about the Python-ideas mailing list