在Python(tkinter)中从类的外部更改类的私有属性(标签)



我用Python中的tkinter制作了一个GUI,我创建了一个名为"窗口";以管理整个会话期间GUI中的所有创建、功能和更改。我不知道我是不是把这件事做得太复杂了,但我正在尝试构建一种方法,这样我就只能从";窗口";类,因为有很多标签,我想制作类似下一个代码的东西(这是一个最小可复制示例(:

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"对象没有属性"label"。

有没有办法做我想做的东西?将我想要更改的标签的名称发送到方法,然后接收它并将其视为属性的名称?

或者我应该只是将标签声明为公共标签,并从类外更改它";窗口"?

问题是有很多标签,我不希望它们被错误地更改,所以我想"简化";改变的过程,但也许我把它弄得太复杂了。

提前感谢您的回复。

如果您想使用字符串访问小部件,您需要通过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()

这里有两个基本问题Python没有私有属性。Python没有任何访问修饰符。您在这里使用的是双下划线名称篡改。这是而不是与private相同。它只是将名称篡改为_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

要使用字符串修改属性,请使用getattrsetattr:

>>> class Foo: pass
...
>>> foo = Foo()
>>> setattr(foo, 'bar', 42)
>>> foo.bar
42
>>> getattr(foo, 'bar')
42

最新更新