在 Python(tkinter)中从类的外部更改类的私有属性(标签)
Posted
技术标签:
【中文标题】在 Python(tkinter)中从类的外部更改类的私有属性(标签)【英文标题】:Changing private attributes (labels) of a Class from outside of it in Python (tkinter) 【发布时间】:2021-08-13 07:26:29 【问题描述】:我在 Python 中使用 tkinter 制作了一个 GUI,我创建了一个名为“Window”的类来管理整个会话期间 GUI 中的所有创建、运行和更改。 我不知道我是否让这太复杂了,但我正在尝试构建一个方法,所以我只能从“Window”类中更改标签,并且因为有很多标签,我想做类似的东西下一个代码(这是一个最小的可重现示例):
from tkinter import *
class Window:
def __init__(self, wind):
self.__window = wind
self.__window.geometry("200x100")
self.__window.title("Title")
self.__label_1 = Label(self.__window, text="Label 1 text")
self.__label_1.pack()
self.__button_1 = Button(self.__window, text="Change", command=function)
self.__button_1.pack()
def change_label(self, label, text): #this 'label' is the name of the label I want to change
self.label["text"] = text #here I try to use it as the attibute's name
def function():
myWindow.change_label("__label_1", "New text")
if __name__=='__main__':
wind = Tk()
myWindow = Window(wind)
wind.mainloop()
我面临的问题显然是:AttributeError, 'Window' object has no attribute 'label'。
有没有办法制作我想要制作的东西?将我要更改的标签名称发送给方法,然后接收它并将其视为属性名称?
或者我应该将标签声明为公共标签并从“Window”类之外更改它?
问题是标签很多,我不希望他们被错误地改变,所以我想“简化”改变的过程,但也许我把它弄得太复杂了。
提前感谢您的回复。
【问题讨论】:
您可以使用实例字典,例如self.__labels =
,来保存标签:self.__labels["__label_1"] = self.__label_1
。然后使用这个字典来更新change_label()
里面需要的标签。
谢谢@acw1668 我对 Python 还很陌生,所以我对“实例字典”感到困惑,我刚刚读了一些东西,但我还是不明白,我无法实现你的解决方案.您的意思是将标签的所有文本值存储在字典中并直接更改这些值吗?但是如何刷新 GUI 以使标签发生变化?
我的意思是类型为 dictionary 的类的实例变量,就像我之前评论中的示例:self.__labels =
。 self.__labels
是实例变量,它的类型是dictionary。
Python 没有私有属性 这是双下划线名称修改。这与 private 不同,Python 没有任何访问修饰符
@juanpa.arrivillaga "__label_1"
只是一个字符串,用作字典中存储或引用标签的键。
【参考方案1】:
如果您想使用字符串访问小部件,您需要通过name
选项提供一个唯一名称。为了更容易访问,最好使用字典来存储小部件,使用它们的名称作为键。
以下是根据您的修改的示例:
from tkinter import *
class Window:
def __init__(self, wind):
self.__window = wind
self.__window.geometry("200x100")
self.__window.title("Title")
self.__widgets = # dictionary to hold the created widgets
# use whatever "name" you want but it must be unique
self.create(Label, text="Label 1 text", name="label_1")
self.create(Button, text="Change", command=function, name="button_change")
def create(self, widget, **kw):
w = widget(self.__window, **kw)
w.pack()
name = kw.get("name", str(w)) # use implicitly created name if "name" option is not given
self.__widgets[name] = w
return name
def change(self, name, **kw):
self.__widgets[name].config(**kw)
def function():
# access the widget using the unique name
myWindow.change("label_1", text="New text", font="Arial 24 bold")
if __name__=='__main__':
wind = Tk()
myWindow = Window(wind)
wind.mainloop()
【讨论】:
这正是我想做的,非常感谢!【参考方案2】:这里有两个基本问题。 Python 没有私有属性。 Python 没有 any 访问修饰符。您在这里使用的是 双下划线名称修饰。这与私有不相同。它只是将名称更改为 _MyClass__my_attribute
以防止子类中的意外名称冲突,它仍然可以从外部完全访问:
>>> class Foo:
... def __init__(self):
... self.__bar = 42
...
>>> foo = Foo()
>>> foo._Foo__bar
42
表示不属于公共 API 的变量的惯用方式是使用 单下划线,例如self._bar = 42
,这可能是您应该在这里使用的。
现在,这种方法永远行不通了:
def change_label(self, label, text): #this 'label' is the name of the label I want to change
self.label["text"] = text #here I try to use it as the attibute's name
你想要的方式。要使用字符串修改属性,请使用getattr
和setattr
:
>>> class Foo: pass
...
>>> foo = Foo()
>>> setattr(foo, 'bar', 42)
>>> foo.bar
42
>>> getattr(foo, 'bar')
42
【讨论】:
以上是关于在 Python(tkinter)中从类的外部更改类的私有属性(标签)的主要内容,如果未能解决你的问题,请参考以下文章