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

问题描述 投票:0回答:3

我需要检查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')
python methods call
3个回答
2
投票

您要么需要:

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

无论哪种方式,您都不能直接进入正在运行的进程并在该进程内触发一个函数(如果将正在运行的进程连接到调试器,则从字面上看这不可能,但我不建议这样做。

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


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停顿下来。

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


0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.