Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Weird closure behavior in python

I have a following simple code:

def get():
    return [lambda: i for i in [1, 2, 3]]

for f in get():
    print(f())

As expected from my python knowledge, output is 3 - entire list will contain last value of i. But how this works internally?

AFAIK, python variables are simply reference to objects, so first closure must enclose object first i reference - and this object is definitely 1, not 3 O_O. How it happens that python closure encloses variable itself instead of object this variable reference? Does it save variable name as plain text, some "reference to variable" or what?

like image 365
grigoryvp Avatar asked Jun 19 '12 21:06

grigoryvp


1 Answers

As @thg435 points out, a lambda will not encapsulate the values at that moment, but rather the scope. There are too small ways you can address this:

lambda default argument "hack"

[ lambda v=i: v for i in [ 1, 2, 3 ] ]

Or use functools.partial

from functools import partial
[ partial(lambda v: v, i) for i in [ 1, 2, 3 ] ]

Essentially you have to move the scope to be local to the function you are creating. Generally I like using partial more often since you can pass it a callable, and any args and kargs to create a callable with a proper closure. Internally, it is wrapping your original callable so the scope is shifted for you.

like image 62
jdi Avatar answered Sep 20 '22 06:09

jdi