如何从已经运行的python脚本调用方法

时间:2014-03-16 02:19:00

标签: python methods call

我需要检查python脚本是否已经在运行,然后从同一个运行的python脚本调用一个方法。但它必须在同一个过程(pid)上,没有新的过程。这可能吗?

我尝试了一些代码但没有工作。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter as tk
from Tkinter import *
import socket


class Main():
    def mainFunc(self):
        self.root = tk.Tk()
        self.root.title("Main Window")

        self.lbl = Label(self.root, text = "First Text")
        self.lbl.pack()

        openStngs = Button(self.root, text = "Open Settings", command=self.settingsFunc)
        openStngs.pack()

    def settingsFunc(self):
        stngsRoot = Toplevel()
        stngsRoot.title("Settings Window")

        changeTextOfLabel = Button(stngsRoot, text = "Change Main Window Text", command=self.change_text)
        changeTextOfLabel.pack()

    def change_text(self):
        self.lbl.config(text="Text changed")

# the get_lock from http://stackoverflow.com/a/7758075/3254912
def get_lock(process_name):
    lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
    try:
        print lock_socket
        lock_socket.bind('\0' + process_name)
        print 'I got the lock'

        m.mainFunc()
        mainloop()

    except socket.error:
        print 'lock exists'
        m.settingsFunc()
        mainloop()
        # sys.exit()

if __name__ == '__main__':
    m=Main()
    get_lock('myPython.py')

3 个答案:

答案 0 :(得分:2)

套接字是解决这种进程间通信问题的好方法。

一种可能的方法是在原始进程的线程中设置套接字服务器,这可以用作外部输入的入口点。一个(相当愚蠢的)例子可能是:

# main.py

import socket
import SocketServer # socketserver in Python 3+
import time
from Queue import Queue
from threading import Thread

# class for handling requests
class QueueHandler(SocketServer.BaseRequestHandler):
    def __init__(self, request, client_address, server):
        self.server = server
        server.client_address = client_address
        SocketServer.BaseRequestHandler.__init__(self,request, client_address, server)

    # receive a block of data
    # put it in a Queue instance
    # send back the block of data (redundant)  
    def handle(self):
        data = self.request.recv(4096)
        self.server.recv_q.put(data)
        self.request.send(data)


class TCPServer(SocketServer.TCPServer):
    def __init__(self, ip, port, handler_class=QueueHandler):
        SocketServer.TCPServer.__init__(self, (ip, port), handler_class, bind_and_activate=False)
        self.recv_q = Queue() # a Queue for data received over the socket
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_bind()
        self.server_activate()

    def shutdown(self):
        SocketServer.TCPServer.shutdown(self)

    def __del__(self):
        self.server_close()


# This is the equivalent of the main body of your original code
class TheClassThatLovesToAdd(object):
    def __init__(self):
        self.value = 1

        # create and instance of the server attached to some port
        self.server = TCPServer("localhost",9999)

        # start it listening in a separate control thread
        self.server_thread = Thread(target=self.server.serve_forever)
        self.server_thread.start()
        self.stop = False

    def add_one_to_value(self):
        self.value += 1

    def run(self):
        while not self.stop:
            print "Value =",self.value

            # if there is stuff in the queue...
            while not self.server.recv_q.empty():

                # read and parse the message from the queue
                msg = self.server.recv_q.get()

                # perform some action based on the message
                if msg == "add":
                    self.add_one_to_value()
                elif msg == "shutdown":
                    self.server.shutdown()
                    self.stop = True

            time.sleep(1)

if __name__ == "__main__":
    x = TheClassThatLovesToAdd()
    x.run()

当你开始这个跑步时,它应该只是循环打印到屏幕上。输出:

Value = 1
Value = 1
Value = 1
...

然而,附加到TCPServer实例的TheClassThatLovesToAdd实例现在为我们提供了一个控制路径。最简单的控制代码片段是:

# control.py

import socket
import sys

sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.settimeout(2)
sock.connect(('localhost',9999))

# send some command line argument through the socket
sock.send(sys.argv[1])
sock.close()

因此,如果我在一个终端窗口中运行main.py并从另一个终端窗口调用python control.py add,则main.py的输出将会更改:

Value = 1
Value = 1
Value = 1
Value = 2
Value = 2
...

最后要杀死它,我们可以运行python control.py shutdown,这会轻轻地让main.py停止。

这绝不是解决问题的唯一方法,但它可能是最简单的解决方案之一。

答案 1 :(得分:1)

您需要:

  • 主动检查正在运行的进程以查看环境(例如,通过套接字传输的文件或数据的内容)以了解何时触发该函数,
  • 或者您的运行过程接收unix信号或其他一些IPC(可能是用户定义的信号之一)并在收到信号时执行功能。

无论哪种方式,你都不能只是进入一个正在运行的进程并在该进程中触发一个函数(如果你将正在运行的进程挂钩到一个调试器,那么可能不可能完全不可能,但我不推荐它。) / p>

Tkinter必然有自己的事件循环系统,所以我建议阅读它是如何工作的,以及如何在该事件循环系统中的定时器上运行某些东西,或者设置一个响应信号的回调。您还可以将一个基于非事件循环的系统包装在try / except块中,该块将捕获由UNIX信号生成的异常,但是在捕获到该信号之后恢复程序其余部分的操作可能并不简单,在那种情况下。

答案 2 :(得分:0)

可以尝试GDB,但不确定如何从[空闲线程]内调用函数。

也许某人非常熟悉gdb并从GDB中调试/调用Python函数可以改善此答案。