Giacomo Boffi wrote: > i have this test program (that i already posted on it.comp.lang.python) > > ----[ test.py ] > from Tkinter import * > > def output(s): > print s > > def doit(fr,lst): > for c1,c2 in zip(lst[::2], lst[1::2]): > subframe=Frame(fr) > Label(subframe,text=c1+' <-> > '+c2).pack(side='left',expand=1,fill='both') > Button(subframe,text='>',command=lambda: output(c1+'->'+c2)).pack() > Button(subframe,text='<',command=lambda: output(c2+'->'+c1)).pack() > subframe.pack(fill='x',expand=1) > > root=Tk() > fr=Frame(root,relief='raised',borderwidth=5).pack(fill='both',expand=1) > doit(fr,['pippo','pluto','paperino','zio_paperone']) > Button(root,text='Q',command=root.destroy).pack(expand=1,fill='x') > root.mainloop() > ---- > > when i execute it from the command line, click on the 4 buttons from > top to bottom and quit (you can do the same), this is what i get > > aiuole: python test.py > gray->black > black->gray > gray->black > black->gray > aiuole: > > as you see, the button 0 and 1 have callbacks different from my > expectations, as my script was intended to give > > cyan->blue > blue->cyan > gray->black > black->gray > > why the messed callbacks? what's the right thing to do?
Closures in python contain names, not the objects they refer to. So when you rebind that name (as you do above in your loop), the created callbacks will only refer to the last bound value of a name. Create new closures, or bind arguments as defaults: funcs = [] def create_func(i): return lambda: i for i in xrange(10): funcs.append(lambda i=i: i) funcs.append(create_func(i)) for f in funcs: print f() Diez -- http://mail.python.org/mailman/listinfo/python-list