user1159817
user1159817

Reputation: 29

Class lambda callback NameError

What am I doing wrong? I want the 'refreshB' button to call the 'update' def but I get a nameError instead

class monitor():
    def update(self):
        print "Called"

    mon = Tk()
    mainFrame = Frame(mon)
    mainFrame.grid(row=1, column=1)

    optionFrame = Frame(mainFrame)
    optionFrame.grid(row=1, column=1)

    refreshB = ttk.Button(optionFrame, text='Refresh', command=lambda: update('self') )
    refreshB.grid(row=1, column=1)

    mon.mainloop()

monitor()


**NameError: global name 'update' is not defined**

I an not very familiar with Classes, is there something else I am supposed to add?

If the script above was not a class then I would use:

refreshB = ttk.Button(optionFrame, text='Refresh', command=lambda: update )

Which would works fine...

Upvotes: 1

Views: 898

Answers (2)

Joel Cornett
Joel Cornett

Reputation: 24788

Place all your initialization code inside an initialization function. Then refer to update() as self.update().

    class Monitor(object):
        def update(self, event):
            print "Called"

        def __init__(self):
            self.mon = Tk()
            self.mainFrame = Frame(self.mon)
            self.mainFrame.grid(row=1, column=1)

            self.optionFrame = Frame(self.mainFrame)
            self.optionFrame.grid(row=1, column=1)

            self.refreshB = ttk.Button(self.optionFrame, text='Refresh', command=self.update)
            self.refreshB.grid(row=1, column=1)

        def run(self):
            self.mon.mainloop()

    monitor = Monitor()
    monitor.run()

the update() reference doesn't work here because it's an instancemethod and not a classmethod. Not because of the use of lambda--although I have no idea why you'd need to use a lambda function anyways. My solution involves you creating an instance of Monitor. This is useful because it allows you to control when the code within Monitor is executed. (Otherwise the code in your class body is executed at definition time. All calling monitor() does is return an instance of the class monitor--it doesn't execute the body of the code)

Upvotes: 1

Celada
Celada

Reputation: 22261

You shouldn't really have code that has side effects directly in a class. You almost certainly want all that code to be in the __init__ function instead, which gets called after your monitor object is created:

def __init__(self):
    mon = Tk()
    etc...

Next, update is an instance method so it has to be called on an object. You probably want this:

refreshB = ttk.Button(optionFrame, text='Refresh', command=lambda: self.update('self') )

But then, since your update method doesn't take any arguments beyond the implicit self argument, you actually probably want this:

refreshB = ttk.Button(optionFrame, text='Refresh', command=lambda: self.update() )

Finally, the lambda is useless indirection. Why don't you just give the method directly as a callback instead of wrapping it in a lambda?

refreshB = ttk.Button(optionFrame, text='Refresh', command=self.update )

Upvotes: 0

Related Questions