1

I have been writing a piece of software that keeps track of homework, written in python. I will give a small snippet which displays all homework's.

def delHomework(homework,element,HLabel,HDelete):
    del homework.get(element)
    HLabel.destroy()
    HDelete.destroy()

row = 0 #keeps track on which height everything is inserted
for i in homeworks: #homeworks is a list of all homework's
    HLabel = Label(text=i) #displays the homework
    HLabel.grid(column=0,row=row)

    HDelete = Button(text="delete",command=lambda: 
        delHomework(homework,i,HLabel,HDelete)
    #is the button to delete the homework

    HDelete.grid(column=1,row=row)

    row += 1

The problem is that even though it all displays correctly, when you try delete any homework, the last is deleted instead of the associated one because the lambda is referencing the newest sate of the variable instead at that iteration and I can't figure out how to make it work. Hope this question makes sense.

Viktor K.
  • 2,670
  • 2
  • 19
  • 30
Lcoder
  • 21
  • 5

2 Answers2

1

Assuming the missing paranthesis for HDelete is just a copy-paste issue.

The actual issue is that the value of i is not computed for the lambda function untill the function gets called, and when it does get called, it uses the latest value of i , in this case, that would be the last value of i from the homworks list.

A very simple example -

>>> lst = [1,2,3,4,5,6]
>>> newlst = []
>>> for i in lst:
...     newlst.append(lambda : print(i))
...
>>> newlst[1]()
6
>>> newlst[2]()
6

You should instead pass in the element as a default argument to lambda. Example -

HDelete = Button(text="delete",command=lambda ele = i, hl = HLabel, hd = HDelete: 
    delHomework(homework,ele,hl,hd))

Example/Demo to show its working -

>>> lst = [1,2,3,4,5,6]
>>> newlst = []
>>> for i in lst:
...     newlst.append(lambda ele = i: print(ele))
...
>>> newlst[2]()
3
>>> newlst[1]()
2
Anand S Kumar
  • 88,551
  • 18
  • 188
  • 176
0

As explained in the accpeted answer in the folowing question: What do (lambda) function closures capture?

You could do something like this:

HDelete = Button(text="delete",command=(lambda i, l, d: lambda:
    delHomework(homeworks, i, l, d))(i, HLabel, HDelete)

or something like this:

def createDeleteCommand(homeworks, i, l, d):
    return lambda: delHomework(homeworks, i, l, d)

HDelete = Button(text="delete",command=
     createDeleteCommand(homeworks, i, HLabel, HDelete))
Community
  • 1
  • 1
AxelWass
  • 1,321
  • 12
  • 21