1

In the code below I intend to have two buttons, and when each is pressed '0' and '1' are to be printed to stdout, respectively. However when the program is run, they both print '1', which is the last value i had in the for iteration. Why?

import Tkinter as tk
import sys

root = tk.Tk()

for i in range(0,2):
    cmd = lambda: sys.stdout.write(str(i))
    tk.Button(text="print '%d'" % i,command=cmd).pack()

root.mainloop()
Amber
  • 507,862
  • 82
  • 626
  • 550
apalopohapa
  • 4,983
  • 5
  • 27
  • 29

3 Answers3

5

The i is not captured in the lambda when you create it (as you wanted). Instead, both functions refer back to the i in the external for loop, which changes after the function is created and before it is run. To capture it, you can use a default value:

for i in range(0,2):
    cmd = lambda i=i: sys.stdout.write(str(i))
    tk.Button(text="print '%d'" % i,command=cmd).pack()
newacct
  • 119,665
  • 29
  • 163
  • 224
3

Surely it's the issue in

On lambdas, capture, and mutability

that comes up over and over...

Brian
  • 117,631
  • 17
  • 236
  • 300
1

I think it's a bit odd to use an anonymous function just to then give it a name. Why not write it like this?

for i in 0,1:
    def cmd():
        return sys.stdout.write(str(i))
    tk.Button(text="print '%d'"%i, command=cmd).pack()
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 1
    @newacct: "for i in 0,1" is correct syntax. Try it in an interactive Python shell and see what happens. – Deestan Jul 01 '10 at 08:56