News for hackers. Stuff that matters.
Re:Lambdas and Functions in Python by UncleEntity on Saturday June 16, 2018 @07:26PM (#17330055)
Python stores the captured variables in __globals__ which is shared with all the different lambdas for some odd reason:

>>> fs[0] == fs[1]

False

>>> fs[0].__globals__ == fs[1].__globals__

True

>>> fs[0].__globals__['i'], fs[1].__globals__['i']

(9, 9)

Kind of weird?

--edit--

  >>> def f(i):
  ...     return lambda n: i + n

  >>> fs = [f(i) for i in range(10)]

  >>> [f(4) for f in fs]
  [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
It works if it has somewhere to store the captured variables so just don't pollute the global environment and all is fine...
Re:Lambdas and Functions in Python by abecedarius on Saturday June 16, 2018 @07:50PM (#17330138)
I think you're looking at Python 2, because in py3 the list comprehensions create a nested scope for the loop variable to be local in. -- i.e. 'i' would be in a local environment, not in globals. This doesn't change the behavior of these particular closures, since i is still mutated in the loop.
Re:Lambdas and Functions in Python by UncleEntity on Saturday June 16, 2018 @07:57PM (#17330161)
Python 3.6.5 (default, Apr 4 2018, 15:01:18)

...even weirder:

>>> fs[0].__closure__ == fs[1].__closure__

True

Re:Lambdas and Functions in Python by abecedarius on Saturday June 16, 2018 @08:02PM (#17330172)
Since I don't have py3 installed at the moment, I can't check anything, but I'd guess this is two closures with distinct ids but the same environments, and == is doing a structural comparison rather than an identity comparison. Wish I could look into it right now.
Re:Lambdas and Functions in Python by UncleEntity on Saturday June 16, 2018 @09:05PM (#17330376)

  >>> fs[0].__closure__, fs[1].__closure__
  ((<cell at 0x7f4e9111b048: int object at 0x7f4e98e99500>,), 
   (<cell at 0x7f4e9111b048: int object at 0x7f4e98e99500>,))
So lambda isn't broken it's the list comprehension going all wonky with its local variables methinks.
Re:Lambdas and Functions in Python by abecedarius on Saturday June 16, 2018 @09:32PM (#17330464)
All right, I looked into this using repl.it. The __closure__ field is not actually a closure in the usual sense of the word -- it's the environment of the closure, and fs[0] and fs[1] are expected to share the same environment. If you look at the identities of fs[0] and fs[1] themselves, they are different. It's as I said originally, just with a confusing name for the environment field.