This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed last year.
Consider the following code:
def A():
l = list()
for i in range(5):
l.append(lambda: i)
return l
for f in A():
print( f() )
It prints out 4 five times, and I'm assuming it does that because the lambda function has taken the variable i through the outer scope of A, but right before the moment the variable became out of scope.
Then we have this code:
def B():
l = list()
for i in range(5):
l.append((lambda i: lambda: i)(i))
return l
for f in B():
print( f() )
It prints out all numbers from 0 to 4 in order. I am assuming it does that because the variable i has been grabbed from the scope of the outer lambda which took it as a parameter, so the value has been assigned to the cell in the moment when that external lambda finished executing.
But what if i held a mutable object instead of an immutable int?
def C():
l, i = list(), list()
for r in range(5):
i.append(r)
l.append((lambda i: lambda: i)(i.copy()))
return l
for f in C():
print( f() )
It does print out the lists in order as expected, because I used the list.copy() method in the argument.
Now, is my understanding correct?
If so, then is there a more pythonic or simpler way to save in a closure cell either an immutable object (or a copy of a mutable object), at the exact moment I want to? In other words, is there a better way than the (lambda i: lambda: i)(i) latch I came up with?
This happens because of late binding, try this code:
def bind(value):
return lambda: value
def A():
l = list()
for i in range(5):
l.append(bind(i))
return l
for f in A():
print( f() )
This way you can obtain the expected behaviour, since the binding is now on a value and not on a variable. Of course this is something tricky, and you should pay attemption to the behaviours of function like this, since python is using late binding.
Related
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
I was surprised that this assertion fails:
x = 42
x = lambda: x
assert x() == 42
It seems that x ends up recursively referring to itself, so that x(), x()(), etc. are all functions.
What is the rule used to parse this, and where is this documented?
By the way (not unexpectedly given the above), the original value of x has no references left after the lambda definition:
class X:
def __del__(self): print('deleting')
x = X()
x = lambda: x # 'deleting' is printed here
The variable x is created by the first assignment, and rebound with the second assignment.
Since the x in the lambda isn't evaluated until the lambda is called, calling it will evaluate to the most recently assigned value.
Note that this is not dynamic scoping - if it were dynamic, the following would print "99", but it prints "<function ...":
x = 42
x = lambda: x
def test(f):
x = 99
print(f())
test(x)
The first assignment is irrelevant; the x in the body of the lambda is bound late:
x = lambda: x # no need for a prior assignment
x = lambda: y # notice: no NameError occurs, *until it is called*
This is the same reason that creating lambdas in a loop is tricky, and is also used to make trees with the standard library defaultdict:
tree = lambda: defaultdict(tree)
t = tree()
t['foo']['bar']['baz'] = 'look ma, no intermediate steps'
A lambda is an anonymous function object. Python completely resolves whatever is on the right side of an equation to a single anonymous object and then resolves whatever is on the left side for assignment.
x = lambda: x
first compiles lambda: x into a function object that returns whatever happens to be in x at the time it is called. It then rebinds x with this function object, deleting whatever object happened to be there before.
Now x is a function that returns whatever is in x... which is a function that returns whatever is in x, etc... So you can write x()()()()()() as many times as you want, and still get that orginal lambda:x function object.
Python functions have a local namespace but only variables assigned in the function reside there. Since x isn't assigned in the lambda, it's resolved in the containing scope - that is, the module level "x". An identical piece of code is
def x():
return x
Contrast this with
def x():
x = 1
return x
Now, the parameter x is a local variable and is unrelated to the global x.
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 2 years ago.
I have a list of functions each of these takes a parameter.
I want to use a function of a library which takes functions but expects them to have no parameters.
So I want to create a list of new functions using lambda to pass the param "externally"
However the new list of functions doesn't yield the expected result.
(This is some minimal example)
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(lambda: fun(0))
return funs_out
funs = [fun_a,fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
#funs_changed = [lambda: f(0) for f in funs]
funs_changed[0]() # prints b ??? expected a
funs_changed[1]() # prints b
I tried funs_changed = [lambda: f(0) for f in funs] before as it seems more pythonic, and then tried to use more explicit code (raw for loop) to find the root cause but without success.
What do I miss?
You can use functools.partial:
from functools import partial
def fun_a(param):
print("a")
def fun_b(param):
print("b")
def do_something(funs):
funs_out = []
for fun in funs:
funs_out.append(partial(fun, 0))
return funs_out
funs = [fun_a, fun_b]
funs[0](0) # prints a
funs[1](0) # prints b
funs_changed = do_something(funs)
# funs_changed = [partial(fun, 0) for f in funs]
funs_changed[0]() # prints a
funs_changed[1]() # prints b
From this answer:
Roughly, partial does something like this (apart from keyword args
support etc):
def partial(func, *part_args):
def wrapper(*extra_args):
args = list(part_args)
args.extend(extra_args)
return func(*args)
return wrapper
just use value hack:
funs_changed = [lambda f=f: f(0) for f in funs]
it would be OK and produce an output of:
a
b
a
b
Also there is a solution for your initial variant of the code: just patch do_something function if you prefer keep it as function to avoid in-line lamda-list comprehention in main code contex (we'll do it in function):
def do_something(funs):
funs_out = [lambda f=f: f(0) for f in funs]
return funs_out
This question already has answers here:
How do I pass a variable by reference?
(39 answers)
Closed 9 years ago.
i need help-i try to send value to method like in c++ by ref/by ptr
how can i do it?
to exmple:
def test(x):
x=3
x=2
test(x)
print(x)
In this case x a local variable in test method and will not change the "original" X
so how can i change the "original" X?
thanks
In some ways, all calls in Python are called with references. In fact, all variables are references in a sense. But some types, like int from your example, cannot be changed.
In the case of, say, a list, the functionality you're looking for is trivial:
def change_it(some_list):
some_list.append("world")
foo = ["hello"]
change_it(foo)
print(foo) # prints ['hello', 'world']
Note, however, that reassigning the parameter variable some_list does not change the value in the calling context.
If you're asking this question, though, you're probably looking to do something like set two or three variables using one function. In that case, you're looking for something like this:
def foo_bar(x, y, z):
return 2*x, 3*y, 4*z
x = 3
y = 4
z = 5
x, y, z = foo_bar(x, y, z)
print(y) # prints 12
Of course, you can do anything in Python, but that doesn't mean you should. In the fashion of the TV show Mythbusters, here's something that does what you're looking for
import inspect
def foo(bar):
frame = inspect.currentframe()
outer = inspect.getouterframes(frame)[1][0]
outer.f_locals[bar] = 2 * outer.f_locals[bar]
a = 15
foo("a")
print(a) # prints 30
or even worse:
import inspect
import re
def foo(bar):
# get the current call stack
my_stack = inspect.stack()
# get the outer frame object off of the stack
outer = my_stack[1][0]
# get the calling line of code; see the inspect module documentation
# only works if the call is not split across multiple lines of code
calling_line = my_stack[1][4][0]
# get this function's name
my_name = my_stack[0][3]
# do a regular expression search for the function call in traditional form
# and extract the name of the first parameter
m = re.search(my_name + "\s*\(\s*(\w+)\s*\)", calling_line)
if m:
# finally, set the variable in the outer context
outer.f_locals[m.group(1)] = 2 * outer.f_locals[m.group(1)]
else:
raise TypeError("Non-traditional function call. Why don't you just"
" give up on pass-by-reference already?")
# now this works like you would expect
a = 15
foo(a)
print(a)
# but then this doesn't work:
baz = foo_bar
baz(a) # raises TypeError
# and this *really*, disastrously doesn't work
a, b = 15, 20
foo_bar, baz = str, foo_bar
baz(b) and foo_bar(a)
print(a, b) # prints 30, 20
Please, please, please, don't do this. I only put it in here to inspire the reader to look into some of the more obscure parts of Python.
As far as I am aware, this doesn't exist in Python (although a similar thing occurs if you pass mutable objects to a function). You would do either
def test():
global x
x = 3
test()
or
def test(x):
return 3
x = test(x)
The second of these is much preferred.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Creating lambda inside a loop
In the code below, invoking any member of the returned array of closures
prints the number 4.
def go():
x = []
for i in range(5):
def y(): print i
x.append(y)
return x
I would like each member of the closure to print the number that i was when the closure was defined.
One way around this is to use default arguments:
def y(i=i):
print i
Default arguments are evaluated when the function is created, not called, so this works as you'd expect.
>>> i = 1
>>> def y(i=i): print i
...
>>> i = 2
>>> y()
1
A little extra info just for fun:
If you're curious what the defaults are, you can always inspect that with the .func_defaults attribute (__defaults__ in python3.x):
>>> y.func_defaults
(1,)
This attribute is also writeable, so you can in fact change the defaults after the function is created by putting a new tuple in there.
This question already has answers here:
What do lambda function closures capture?
(7 answers)
Closed 6 months ago.
Why does this attempt at creating a list of curried functions not work?
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
a.append(lambda x: p (i, x))
return a
>>> myList = test()
>>> test[0]('test')
9 test
>>> test[5]('test')
9 test
>>> test[9]('test')
9 test
What's going on here?
A function that actually does what I expect the above function to do is:
import functools
def test2():
a = []
for i in range (10):
a.append(functools.partial(p, i))
return a
>>> a[0]('test')
0 test
>>> a[5]('test')
5 test
>>> a[9]('test')
9 test
In Python, variables created in loops and branches aren't scoped. All of the functions you're creating with lambda have a reference to the same i variable, which is set to 9 on the last iteration of the loop.
The solution is to create a function which returns a function, thus scoping the iterator variable. This is why the functools.partial() approach works. For example:
def test():
def makefunc(i):
return lambda x: p(i, x)
a = []
for i in range(10):
a.append(makefunc(i))
return a
Well you can also bind the i to an outer lambda for the lazy.
def p(x, num):
print x, num
def test():
a = []
for i in range(10):
a.append((lambda i :lambda x: p (i, x))(i))
return a
I was always confused as to why this doesn't work. Thanks for the explanation, 'a paid nerd'. I personally prefer this solution:
for i in range(10):
a.append(lambda num, val_i=i: p (val_i, num))
Note the val_i=i default argument of the lambda that enables to capture the instantaneous value of i during the loop whilst still effectively making lambda a function of 1 variable. (BTW: changed your x into num to match p's definition.) I like it better because:
it is very close to the original idea and avoids having to define a new named function, precisely the purpose of a lambda...
avoids importing functools
and avoids imbricating lambdas...
Just did a search and found more detailed explanations for the same problem there: Scope of python lambda functions and their parameters
I asked a similar question, and got two answers. One basically the same as the accepted answer here, and the other which is less clear but slightly more succint.
Dynamically creating a menu in Tkinter. (lambda expressions?)