Behaviour I don't understand in Python mixings comprehension lists and lambda-functions -
this question has answer here:
i don't understand behaviour of piece of code, involving comprehension list on lambda functions call method in different objects. happened in large program, question made nonsensical toy-case show point:
class evaluator(object): def __init__(self, lft, rgt): self.lft = lft self.rgt = rgt def eval(self, x): return self.lft + x * (self.rgt - self.lft) if __name__ == "__main__": ev1 = evaluator(2, 3) ev2 = evaluator(4, 5) ev3 = evaluator(6, 7) funcs = [lambda x:ev.eval(x+0.1) ev in (ev1, ev2, ev3)] print([f(0.5) f in funcs])
the output [6.6, 6.6, 6.6]
, means method in ev3
1 being evaluated time. instead of [2.6, 4.6, 6.6]
, have expected. surprises me if rid of lambda-function, behaviour fine:
class evaluator(object): def __init__(self, lft, rgt): self.lft = lft self.rgt = rgt def eval(self, x): return self.lft + x * (self.rgt - self.lft) if __name__ == "__main__": ev1 = evaluator(2, 3) ev2 = evaluator(4, 5) ev3 = evaluator(6, 7) funcs = [ev.eval ev in (ev1, ev2, ev3)] print([f(0.5) f in funcs])
returns [2.5, 4.5, 6.5]
. can explain going on here? , how should code in pythoninstic way?
the problem ever evaluating ev at time call function. thus, it's using whatever value ev
has when start print statement. of course, time ev
has value of last function in list.
this no different if had done this:
funcs = [lambda x: ev.eval(x+0.1), lambda x: ev.eval(x+0.1), lambda x: ev.eval(x+0.1)]
notice how use ev
, , use same ev
@ time run functions.
to want, need bind ev
current value in list comprehension @ time define comprehension, can passing in value through lambda arguments:
funcs = [lambda x, ev=ev: ev.eval(x+0.1) ev in (ev1, ev2, ev3)]
however, suggest not this. have experienced, such code hard understand , debug. win no points cramming functionality single line possible.
the technical term closure. more information, check out question on stackoverflow: why aren't python nested functions called closures?
Comments
Post a Comment