在 Python (tkinter) 中从外部更改 Class 的私有属性(标签)
Changing private attributes (labels) of a Class from outside of it in Python (tkinter)
我在 Python 中使用 tkinter 制作了一个 GUI,我创建了一个名为“Window”的 Class 来管理整个会话期间 GUI 中的所有创建、运行和更改。
我不知道我是不是把它弄得太复杂了,但我正在尝试构建一种方法,这样我只能从“Window”class 中更改标签,因为有很多标签,我想制作类似下一个代码的东西(这是一个最小的可重现示例):
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'。
有没有办法制作我想制作的东西?将我要更改的标签的名称发送到方法,接收它并将其视为属性名称?
或者我应该只将标签声明为 public 并从 class“Window”之外更改它?
问题是标签很多,不想被误改,所以想“简化”改的过程,但可能是我弄得太复杂了。
提前感谢您的回复。
这里有两个基本问题。 Python 没有私有属性。 Python 没有 any 访问修饰符。您在这里使用的是双下划线名称修改。那就是不和private一样。它只是简单地将名称改造成 _MyClass__my_attribute
以防止子类中的意外名称冲突,它仍然可以从外部完全访问:
>>> class Foo:
... def __init__(self):
... self.__bar = 42
...
>>> foo = Foo()
>>> foo._Foo__bar
42
表示不属于 public 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
如果您想使用字符串访问小部件,您需要通过 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 中使用 tkinter 制作了一个 GUI,我创建了一个名为“Window”的 Class 来管理整个会话期间 GUI 中的所有创建、运行和更改。 我不知道我是不是把它弄得太复杂了,但我正在尝试构建一种方法,这样我只能从“Window”class 中更改标签,因为有很多标签,我想制作类似下一个代码的东西(这是一个最小的可重现示例):
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'。
有没有办法制作我想制作的东西?将我要更改的标签的名称发送到方法,接收它并将其视为属性名称?
或者我应该只将标签声明为 public 并从 class“Window”之外更改它?
问题是标签很多,不想被误改,所以想“简化”改的过程,但可能是我弄得太复杂了。
提前感谢您的回复。
这里有两个基本问题。 Python 没有私有属性。 Python 没有 any 访问修饰符。您在这里使用的是双下划线名称修改。那就是不和private一样。它只是简单地将名称改造成 _MyClass__my_attribute
以防止子类中的意外名称冲突,它仍然可以从外部完全访问:
>>> class Foo:
... def __init__(self):
... self.__bar = 42
...
>>> foo = Foo()
>>> foo._Foo__bar
42
表示不属于 public 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
如果您想使用字符串访问小部件,您需要通过 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()