[Python-ideas] Explicit variable capture list
Steven D'Aprano
steve at pearwood.info
Tue Jan 19 18:51:15 EST 2016
On Tue, Jan 19, 2016 at 03:10:35PM +0100, 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};
For the benefit of those who don't speak C++, could you explain what
that does? Are C++ name binding semantics the same as Python's?
Specifically, inside fun, does "a" refer to the global a? If you rebind
global a, what happens to fun?
fun(0, 0) # returns 6
a = 0
fun(0, 0) # returns 5 or 6?
> 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)
I cannot tell whether the C++ semantics above are the same as the Python
semantics here. Andrew's response to you suggests that it is not.
> My proposal: create a special variable qualifier (like global and
> nonlocal) to automatically capture variables
"Variables" is an ambiguous term. I don't want to get into a debate
about "Python doesn't have variables", but it's not clear what you mean
here. Python certainly has names, and values, and when you talk about
"variables" do you mean the name or the value or both?
> 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.
If I have understood you correctly, we can already do that in
Python, and don't even need a closure:
a, b, c = 1, 2, 3
fun = lambda x, y, a=a, b=b, c=c: a + b + c + x + y
will capture the current *value* of GLOBAL a, b and c, store them as
default values, and use them as the LOCAL a, b and c.
You may consider it a strength or a weakness that they are exposed as
regular function parameters:
fun(x, y) # intended call signature
fun(x, y, a, b, c) # actual call signature
but if you really care about hiding the extra parameters, a second
approach will work:
from functools import partial
a, b, c = 1, 2, 3
fun = partial(lambda a, b, c, x, y: a + b + c + x + y, a, b, c)
If a, b, c are mutable objects, you can make a copy of the value:
fun = partial(lambda a, b, c, x, y: a + b + c + x + y,
a, b, copy.copy(c)
)
for example.
Does your proposal behave any differently from these examples?
--
Steve
More information about the Python-ideas
mailing list