This is a sort of a follow-up on an old answer to a question about the necessity of functools.partial : while that answer very clearly explains the phenomenon and the basic reason for it, there are still some unclear points to me.
To recap, the following Python code
myfuns = [lambda arg: str(arg) + str(clo) for clo in range(4)]
try :
clo
except NameError :
print("there is no clo")
for arg in range(4) :
print(myfuns[arg](arg), end=", ")
gives 03, 13, 23, 33,
, while the similar OCaml code
let myfuns = Array.map (fun clo -> fun arg -> (string_of_int arg) ^ (string_of_int clo)) [|0;1;2;3|];;
(* there is obviously no clo variable here *)
for arg = 0 to 3 do
print_string (myfuns.(arg) arg); print_string ", "
done;;
gives 00, 11, 22, 33,
.
I understand this is related to a different notion of closure applied to lambda arg: str(arg) + str(clo)
and its correspondent fun arg -> (string_of_int arg) ^ (string_of_int clo)
.
In OCaml, the closure maps the identifier clo
to the value of the variable clo
in the outer scope at the time of creation of the closure. In Python, the closure somehow contains the variable clo
per se, which explains that it gets affected by the incrementation caused by the for
generator.
Is this correct ?
How is this done ? The clo
variable does not exist in the global scope, as evidenced by my try
/except
construct. Generally, I would assume that the variable of a generator is local to it and so does not survive it. So, again, where is clo
? This answer gives insight about __closure__
but I still do not completely grasp how it manages to refer to the clo
variable per se during the generation.
Also, beside this strange behaviour (for people used to statically binding languages), are there other caveats one should be aware of ?