如何在一个Python脚本中控制/调用另一个Python脚本?

3 投票
3 回答
2378 浏览
提问于 2025-04-16 02:47

我正在做一个图形界面程序,原本打算把一个需要长时间运行的任务放在一个事件里,但我发现这样会导致整个程序卡住。因此,听取了别人的建议后,我决定让图形界面只负责启动、停止和监控这个任务,而把长时间运行的任务放在一个单独的脚本里。我知道在一个脚本中运行另一个脚本的方法就是通过导入,但我想知道还有没有其他方法可以和另一个脚本进行沟通,比如读取另一个脚本的输出,并在任何时候终止它?

3 个回答

1

其实有更好的方法来实现这个,而不是直接读取标准输出。你可以看看这个链接了解更多信息:http://docs.python.org/library/multiprocessing.html

1

如果你需要通过标准输入和标准输出进行交流,那么你应该使用 subprocess 模块。

5

我建议你看看这个线程模块。通过继承Thread类,你可以为那些需要花费较长时间的工作创建新的线程。

然后,在这些线程之间进行通信时,你可以使用pubsub或者pydispatcher。我没有尝试过后者,所以不能评论,但我推荐pubsub,因为它使用起来很简单,而且它是wxpython的一部分,这也是个额外的好处。

这里有一个关于在wxpython中运行长时间任务的wiki页面,如果你想要最简单的线程使用示例,可以直接跳到最后。


这里有一个简单的(可运行的)例子,展示了如何使用pubsub从你的工作线程向你的GUI发送消息。

import time

import wx
from threading import Thread
from wx.lib.pubsub import Publisher

class WorkerThread(Thread):
    def __init__(self):
        Thread.__init__(self)

        #A flag that can be set 
        #to tell the thread to end
        self.stop_flag = False

        #This calls the run() to start the new thread
        self.start()


    def run(self):
        """ Over-rides the super-classes run()"""
        #Put everything in here that 
        #you want to run in your new thread

        #e.g...
        for x in range(20):
            if self.stop_flag:
                break
            time.sleep(1)
            #Broadcast a message to who ever's listening
            Publisher.sendMessage("your_topic_name", x)
        Publisher.sendMessage("your_topic_name", "finished")


    def stop(self):
        """
        Call this method to tell the thread to stop
        """
        self.stop_flag = True




class GUI(wx.Frame):
    def __init__(self, parent, id=-1,title=""):
        wx.Frame.__init__(self, parent, id, title, size=(140,180))
        self.SetMinSize((140,180)) 
        panel = wx.Panel(id=wx.ID_ANY, name=u'mainPanel', parent=self)

        #Subscribe to messages from the workerThread
        Publisher().subscribe(self.your_message_handler, "your_topic_name")

        #A button to start the workerThread
        self.startButton = wx.Button(panel, wx.ID_ANY, 'Start thread')
        self.Bind(wx.EVT_BUTTON,  self.onStart, self.startButton)

        #A button to stop the workerThread
        self.stopButton = wx.Button(panel, wx.ID_ANY, 'Stop thread')
        self.Bind(wx.EVT_BUTTON,  self.onStop, self.stopButton)

        #A text control to display messages from the worker thread
        self.threadMessage = wx.TextCtrl(panel, wx.ID_ANY, '', size=(75, 20))

        #Do the layout
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.startButton, 0, wx.ALL, 10)
        sizer.Add(self.stopButton, 0, wx.ALL, 10)
        sizer.Add(self.threadMessage, 0, wx.ALL, 10)
        panel.SetSizerAndFit(sizer)


    def onStart(self, event):
        #Start the worker thread
        self.worker = WorkerThread()

        #Disable any widgets which could affect your thread
        self.startButton.Disable()

    def onStop(self, message):
        self.worker.stop()

    def your_message_handler(self, message):
        message_data = message.data
        if message_data == 'finished':
            self.startButton.Enable()
            self.threadMessage.SetLabel(str(message_data))
        else:
            self.threadMessage.SetLabel(str(message_data))

if __name__ == "__main__":

    app = wx.PySimpleApp()
    frame = GUI(None, wx.ID_ANY, 'Threading Example')
    frame.Show()
    app.MainLoop()

撰写回答