用Python编写模块化代码

4

你好,下面是一个简单的GUI界面,里面有两个按钮。我已经编写了一个方法,用于在按钮被点击后更改按钮上的文本。我希望将该方法模块化并通用化,以便可以将该方法应用于任何按钮而无需重写。在下面的示例中,如何将printWow()方法应用于按钮2而不定义新的方法?

import sys
from PyQt4.Qt import *

class MainWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.cw = QWidget(self)
        self.setCentralWidget(self.cw)
        self.btn1 = QPushButton("Click me", self.cw)
        self.btn1.setGeometry(QRect(50, 50, 100, 30))
        self.btn1.clicked.connect(self.printWow)

        self.btn2 = QPushButton("Click me", self.cw)
        self.btn2.setGeometry(QRect(50, 20, 100, 30))
        self.btn2.clicked.connect(self.printWow)

    def printWow(self):
        self.btn1.setText("WoW")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    myapp = MainWindow()
    myapp.show()
    sys.exit(app.exec_())
2个回答

1
您可以使用 sender() 方法确定哪个按钮被点击了。
返回发出信号的对象的指针,如果在由信号激活的插槽中调用,则返回 0。该指针仅在调用此函数的插槽执行期间从此对象的线程上下文中有效。
如果发送者被销毁或插槽与发送者的信号断开连接,则此函数返回的指针将变为无效。
但是,文档中有一个重要的警告,这与您帖子的标题相冲突:
警告:此函数违反了面向对象的模块化原则。但是,在许多信号连接到单个插槽时,获取对发送者的访问可能会很有用。
您可以像这样使用sender():
def printWow(self):
    self.sender().setText("WoW")

1

基本上,使函数“更通用”意味着识别不同用例中的变体和不变量。在您的示例中,变体将是您要调用setText()的对象以及最终的文本,因此您的“通用”函数将类似于:

def printText(self, target, text="wow"):
    target.setText(text)

既然你不能将这些参数传递给connect()(至少在我们的示例中是这样假设的),那么你需要将通用函数的引用和参数一起封装到一个可以无需参数调用的东西中。这是“部分求值”的一个示例,最简单的形式只需要一个lambda即可:

class MainWindow(QMainWindow):
    def __init__(self, *args):
        QMainWindow.__init__(self, *args)
        self.cw = QWidget(self)
        self.setCentralWidget(self.cw)
        self.btn1 = QPushButton("Click me", self.cw)
        self.btn1.setGeometry(QRect(50, 50, 100, 30))
        self.btn1.clicked.connect(lambda: self.printWow(self.btn1))

        self.btn2 = QPushButton("Click me", self.cw)
        self.btn2.setGeometry(QRect(50, 20, 100, 30))
        self.btn2.clicked.connect(lambda: self.printText(self.btn2, "Yay!"))

    def printText(self, target, text="wow"):
        target.setText(text)

请注意,在上面的例子中,您不会从额外的复杂性中获得太多好处 - 您可以将所有内容都放在lambda中,例如:
self.btn1.clicked.connect(lambda: self.btn1.setText("Wow"))
self.btn2.clicked.connect(lambda: self.btn2.setText("Yay !"))

但我猜你心里想的更复杂一些...现在既然你提到了 "模块化"(至少在你的标题中),那么实现 "模块化" 代码的真正关键不仅仅是将公共代码提取出来,而且主要是将代码拆分为良好解耦的模块,每个模块都有清晰和独立的职责。一个经典的例子是将 UI 代码与 "领域" 代码分离 - 真正完成工作的代码根本不应该知道 UI 的存在...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接