0

我正在阅读 Roger Stuckey 的 wxPython Multiprocessing 代码,试图自己制作一个类似的程序。完整的代码可以在这里找到。

代码运行良好,无需任何修改。但是,我发现在 GUI 类MyFrame和处理类TaskSErverMP之间传递了一个参数self.update。我已经在整个代码片段中进行了搜索,但无法弄清楚它在代码中做了什么——它从来没有被初始化和使用过。

在 MyFrame 类中:

def OnStart(self, event):
   ...
   self.taskserver.processTasks(self.update)
   ...

def OnStop(self, event):
   ...
   self.taskserver.processStop(self.update)
   ...

def update(self, output):
    """
    Get and print the results from one completed task.
    """
    self.output_tc.AppendText('%s [%d] calculate(%d) = %.2f\n'...
    ...
    # Give the user an opportunity to interact
    wx.YieldIfNeeded()

在 TaskServerMP 类中:

def run(self):
   ...
   self.processTasks(self.update)
   ...

def processTasks(self, resfunc=None):
   ...

def processStop(self, resfunc=None): 
   ...

def update(self, output):
    """
    Get and print the results from one completed task.
    """
    sys.stdout.write('%s [%d] calculate(%d) = %.2f' % ....

所以我认为这是一种依赖注入实践,仅此而已。然后我从代码中删除它,最奇怪的事情发生了——程序不再工作了!我显示了 GUI,并且能够开始处理。但是,GUI 刚刚挂起,然后 Windows 报告该程序没有响应。我最终从 Windows 任务管理器中手动杀死了所有 pythonw.exe 进程。

然后我开始考虑是否与TaskServerMP类中的processTasksprocessStop函数的签名有关。但我真的不知道如何将参数self.update关联到可选参数resfunc

我认为 Roger 的代码没有任何问题。但是,如果我不能扭曲源代码来测试我对代码的理解,那我会很困扰。

我在 Windows 7 中使用 Python 2.7。

4

1 回答 1

2

MyFrame.update是一种方法。你可以在第 365 行看到它的定义。

绑定方法也是如此self.update,这意味着它可以像普通函数一样被调用。

你可以看到它processTasks带有一个resfunc参数;然后,至少 165,如果它有一个函数或方法作为该resfunc参数,它会调用它。

这里的想法是让processTasks调用者决定如何在每个任务完成时打印出进度更新。一类可能通过将它们写入标准输出来做到这一点。不同的类可能会更新 GUI 进度条。

这是在 Python 代码中传递回调的一种非常典型的方式。


那么,如果您取出 ,为什么程序会挂起self.update?好吧,看看里面有什么,在第 372 行:

    # Give the user an opportunity to interact
    wx.YieldIfNeeded()

在 wx 中,与大多数 GUI 框架一样,主线程正在运行一个“事件循环”,它必须在每个事件(鼠标移动、按键等)进入时对其进行处理,然后等待下一个事件。你把你的代码写成一堆事件处理程序——当有人点击这个按钮时,运行那个函数;等等。您的事件处理程序必须快速返回。否则,事件循环将无法接收并分派下一个事件,因此您的 GUI 没有响应。在 wx 中,Yield函数族使生活更轻松。只要您经常屈服,您就不必快速返回。但是你仍然必须做一个或另一个——要么早点返回,要么屈服——否则 GUI 将挂起。


这是一个非常简单的示例,展示了如何使用绑定方法:

class Foo(object):
    def __init__(self, name):
        self.name = name
    def print_name(self):
        print(self.name)
    def give_me_a_printer_function(self):
        return self.print_name

spam = Foo('Spam')
my_function1 = spam.print_name
my_function2 = spam.give_me_a_printer_function()
my_function1()
my_function2()

这将打印Spam两次。

函数和方法是Python 中的一等值——您可以传递它们,就像传递数字、字符串、列表和类实例一样。你甚至可以将它们打印出来(虽然你会得到一些像 的丑陋的东西<bound method Foo.print_name of <__main__.Foo object at 0x104629190>>)。

于 2013-03-16T06:59:17.277 回答