Python 使用 lambda 命令时出现 tkinter NameError
Python tkinter NameError when using lambda command
我是 Python 的 tkinter
模块的新手,所以我将不胜感激任何帮助,甚至是解释为什么这是不可能的(如果是这样的话)。
我有一个 (foo, bar, x, y)
形式的 4 元组列表;像这样:
TUPLE_LIST = [('Hello', 'World', 0, 0),
('Hovercraft', 'Eels', 50, 100),
etc.]
和稍后的 for
循环理想地将变量 foo
实例化为带有文本 bar
的按钮,每个按钮都有添加其各自 [=19= 的功能] 到一个已定义的 Entry
小部件,然后将其放置在坐标 x, y
:
for foo, bar, x, y in TUPLE_LIST:
exec("{0} = Button(self, text='{1}', command=lambda: self.update_text('{1}'))".format(foo, bar))
eval(name).place(x=x, y=y)
按钮位置完美,但如果我点击其中一个按钮,我会收到以下错误:
Traceback (most recent call last):
File "...\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "<string>", line 1, in <lambda>
NameError: name 'self' is not defined
我猜这与命令是用 lambda 定义的事实有关,因此本身并不是定义的 'function',但我看到其他人定义了他们的按钮命令与 lambdas。那么它也与使用 exec
有关吗?此外,这是 update_text
的代码(如果重要的话):
def update_text(self, new_char):
old_str = self.text_box_str.get()
# Above is a StringVar() defined in __init__ and used as textvariable in Entry widget creation.
self.text_box_str.set(old_str + new_char)
如有任何帮助,我们将不胜感激。提前致谢。
这是一个非常糟糕的主意。根本没有理由去动态创建变量名。它使您的代码更复杂、更难维护和更难阅读。
如果您想按名称引用小部件,请使用字典:
buttons = {}
for foo, bar, x, y in TUPLE_LIST:
buttons[foo] = Button(self, text=bar, ...)
buttons[foo].place(...)
至于 self
的问题,没有足够的代码说明问题所在。如果您使用 类,代码看起来没问题。如果不是,则不应使用 self
。
要创建更新小部件的函数,您只需将小部件或小部件的名称传递给该函数即可。不清楚您要更新哪个小部件。它似乎是一个条目小部件。我不知道您是否有一个所有按钮都必须更新的条目小部件,或者每个按钮一个条目。我假设是前者。
在下面的示例中,我将展示如何将要更改的变量以及要添加的文本传递给函数。该解决方案不使用 textvariable
属性,但您可以根据需要使用。只需传递它而不是小部件。
buttons[foo] = Button(..., command=lambda widget=self.text_box, value=bar: self.update_text(widget, value))
...
def update_text(self, widget, value):
old_value = widget.get()
new_value = old_value + value
widget.delete(0, "end")
widget.insert(0, new_value)
当然,如果您所做的只是附加字符串,您可以将这四行替换为 widget.insert("end", value)
我是 Python 的 tkinter
模块的新手,所以我将不胜感激任何帮助,甚至是解释为什么这是不可能的(如果是这样的话)。
我有一个 (foo, bar, x, y)
形式的 4 元组列表;像这样:
TUPLE_LIST = [('Hello', 'World', 0, 0),
('Hovercraft', 'Eels', 50, 100),
etc.]
和稍后的 for
循环理想地将变量 foo
实例化为带有文本 bar
的按钮,每个按钮都有添加其各自 [=19= 的功能] 到一个已定义的 Entry
小部件,然后将其放置在坐标 x, y
:
for foo, bar, x, y in TUPLE_LIST:
exec("{0} = Button(self, text='{1}', command=lambda: self.update_text('{1}'))".format(foo, bar))
eval(name).place(x=x, y=y)
按钮位置完美,但如果我点击其中一个按钮,我会收到以下错误:
Traceback (most recent call last):
File "...\lib\tkinter\__init__.py", line 1550, in __call__
return self.func(*args)
File "<string>", line 1, in <lambda>
NameError: name 'self' is not defined
我猜这与命令是用 lambda 定义的事实有关,因此本身并不是定义的 'function',但我看到其他人定义了他们的按钮命令与 lambdas。那么它也与使用 exec
有关吗?此外,这是 update_text
的代码(如果重要的话):
def update_text(self, new_char):
old_str = self.text_box_str.get()
# Above is a StringVar() defined in __init__ and used as textvariable in Entry widget creation.
self.text_box_str.set(old_str + new_char)
如有任何帮助,我们将不胜感激。提前致谢。
这是一个非常糟糕的主意。根本没有理由去动态创建变量名。它使您的代码更复杂、更难维护和更难阅读。
如果您想按名称引用小部件,请使用字典:
buttons = {}
for foo, bar, x, y in TUPLE_LIST:
buttons[foo] = Button(self, text=bar, ...)
buttons[foo].place(...)
至于 self
的问题,没有足够的代码说明问题所在。如果您使用 类,代码看起来没问题。如果不是,则不应使用 self
。
要创建更新小部件的函数,您只需将小部件或小部件的名称传递给该函数即可。不清楚您要更新哪个小部件。它似乎是一个条目小部件。我不知道您是否有一个所有按钮都必须更新的条目小部件,或者每个按钮一个条目。我假设是前者。
在下面的示例中,我将展示如何将要更改的变量以及要添加的文本传递给函数。该解决方案不使用 textvariable
属性,但您可以根据需要使用。只需传递它而不是小部件。
buttons[foo] = Button(..., command=lambda widget=self.text_box, value=bar: self.update_text(widget, value))
...
def update_text(self, widget, value):
old_value = widget.get()
new_value = old_value + value
widget.delete(0, "end")
widget.insert(0, new_value)
当然,如果您所做的只是附加字符串,您可以将这四行替换为 widget.insert("end", value)