一个非常大的__init__有问题吗?
我正在用Python写一个图形用户界面(GUI),这个界面是用Tkinter模块搭建的。我使用一个类来定义这个GUI,因为这样可以更方便地给按钮传递命令,也让整个代码更容易理解。
我的GUI初始化部分大约有150行代码。为了让这部分更容易理解,我把__init__
函数写成了这样:
def __init__(self, root):
self.root = root
self._init_menu()
self._init_connectbar()
self._init_usertree()
self._init_remotetree()
self._init_bottom()
在这里,_init_menu()
、_init_connectbar()
等等负责所有的初始化工作。这样做让我的代码更容易跟上,也避免了__init__
变得太复杂。
不过,这样做也带来了作用域的问题。因为我在_init_connectbar()
中定义的一个输入框(Entry widget)是在这个函数的作用域内,而不是类的属性,所以我在类的其他方法中无法引用它。
我可以通过在__init__
中做大部分初始化来解决这些问题,但这样我就失去了最开始那种结构清晰的好处。
我应该扩展__init__
,还是找其他方法把这些控件引入到类的作用域中呢?
4 个回答
在我看来,你应该把小部件(widgets)存储为实例变量,这样你就可以在任何方法中引用它们。就像大多数编程语言一样,当函数变得太大时,代码的可读性就会下降,所以你把初始化代码拆分开的做法是个好主意。
当一个类的内容太多,放不下一个源文件时,你也可以通过使用混合类(mix-in classes)来拆分这个类,这有点像C#中的部分类(partial classes)。
举个例子:
class MainGuiClass(GuiMixin_FunctionalityA, GuiMixin_FunctionalityB):
def __init__(self):
GuiMixin_FunctionalityA.__init__(self)
GuiMixin_FunctionalityB.__init__(self)
当图形用户界面(GUI)包含不同功能时,这种做法就特别有用,比如有一个配置标签、一个执行标签等等。
你可以选择把一些小部件的引用存储在实例变量里,或者把它们返回(不过要注意只返回最少的一部分;这样可以减少耦合)。然后在__init__
方法里把这些引用存储在局部变量中,再把相关的引用作为参数传递给后面的构造辅助函数。后者的做法更简洁,但需要确保各个部分之间的关系足够松散,这样才能创建一个合理的顺序来实现这一点。
为什么不把你需要引用的小部件(widgets)做成实例变量呢?我通常都是这么做的,这似乎是一个很常见的方法。
比如:
self.some_widget