0

I just debugged my code and traced the problem down to a list comprehension. The result of that code puzzles me, can somebody explain to me why this happens?

take this code:

random.seed(100)

seeds = [random.randint(0, 10000) for i in range(1, 51)]

feature_functions = [lambda image: random_voxel.random_voxel(image, seed) for seed in seeds]

it is supposed to generate 50 functions from the same function using different seeds. however, each and every lambda in the resulting list uses the last seed from ´seeds´ as seed. Can someone explain why this happens?

for example [seed for seed in seeds] prints seeds nicely.

Xaser
  • 2,066
  • 2
  • 22
  • 45
  • 1
    This is a very common "gotcha" stemming from pythons late-binding in closures. – mgilson Oct 25 '16 at 16:57
  • 1
    Change to `feature_functions = [lambda image: random_voxel.random_voxel(image, seed=seed) for seed in seeds]` – Steven Rumbalski Oct 25 '16 at 16:58
  • 1
    Python looks up the variable name at the time the function is called, not when it is created. Using a default argument works because default arguments are evaluated when the function is created, not when it is called. This is not unique to `lambda` functions. Regular functions using the `def` statement work the same way. – Steven Rumbalski Oct 25 '16 at 17:00
  • @StevenRumbalski unfortunately, that didn't do it – Xaser Oct 25 '16 at 17:00
  • For further info, please see [Why do my lambda functions or nested functions created in a loop all use the last loop value when called?](http://sopython.com/canon/30/why-do-my-lambda-functions-or-nested-functions-created-in-a-loop-all-use-the-las/) – PM 2Ring Oct 25 '16 at 17:00
  • 2
    How about `[lambda image, seed=seed: random_voxel.random_voxel(image, seed) for seed in seeds]` ? – PM 2Ring Oct 25 '16 at 17:02
  • @PM2Ring that did the trick, thank you – Xaser Oct 25 '16 at 17:04
  • 1
    Oops. I should have written: `feature_functions = [lambda image, seed=seed: random_voxel.random_voxel(image, seed) for seed in seeds]`. I see this question often enough that I posted the solution on autopilot. :( The key is to bind the value of `seed` to the lambda function when it is created by making it a default value. That is why `seed=seed` is added. – Steven Rumbalski Oct 25 '16 at 17:04

0 Answers0