通过更改 sys.stdout 变量在 2 个 python 进程之间进行通信

Communicating between 2 python processes by changing sys.stdout variable

提问人:ABD 提问时间:8/20/2023 更新时间:8/20/2023 访问量:32

问:

我已经推了这个,但对我提出的解决方案感觉不好。 这是问题: 我创建了一个运行良好的命令行实用程序。

例如:我的 main.py 文件是


def Parser():
    description = textwrap.dedent(
        '''Main Command Line Tool.
     For GUI based tool use: `main-gui`''')
    parser = argparse.ArgumentParser(description=description, prog="main")
    parser.add_argument("-f", "--foo", type=str, required=True, help='foo help')
    parser.add_argument("-b", "--bar", type=str, help='bar help')
    ...

    # this will not be shown in help
    parser.add_argument("--GUI", action="store_true", help=argparse.SUPPRESS)
    return parser

def task(args):
    ...
    print("I am doing the task, Alright!") # this means print will call sys.stdout.write function
    if args.GUI:
       if hasattr(sys.stdout, "set_progress"): # double check. But this is always True if args.GUI is True
           sys.stdout.set_progress(value)
    ...
def main():
    parser = Parser()
    args = parser.parse_args()
    result = task(args)

if __name__ == "__main__":
    main()

我运行它 哪个在终端/控制台/shell 中打印某些文本。基本上是 sys.stdoutmain --foo Hello --bar World

现在,我被要求为相同的 GUI 制作 GUI,所以我使用了 PySide6

这是我 gui.py 文件:

import threading
from easydict import EasyDict
from PySide6.QtCore import ...
from PySide6.QtGui import ...
from PySide6.QtWidgets import ...

from main import main

class EmittingStream(QObject):
    textWritten = Signal(str)
    progress = Signal(int)
    def write(self, text):
        self.textWritten.emit(text)

    def set_progress(self, value):
        self.progress.emit(value)

    def flush(self):
        pass

class GUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.initArgs()
        self.link_actions()

    def initUI(self):
        ...
        self.ui.progress_bar.setValue(0)

    def initArgs(self):
        self.args = EasyDict()
        self.args.foo = None
        self.args.bar = None

    def link_actions(self):
        ...
        self.ui.start_button.clicked.connect(self.start)

    def setProgress(self, progress):
        self.ui.progress_bar.setValue(progress)

    def showOuput(self, s):
        self.ui.output_textedit.append(s)

    def clear_output_textedit(self):
        self.ui.output_textedit.clear()

    def get_args(self):
        # Use the Gui text fields to access the foo and bar argument
        # so self.arg.foo = Hello and so on for all arguments
        # the arguments are exactly the same as the ones used for argparse
 
    def start(self):
        self.get_args()
        command = ["main"]
        command.extend(["--foo", self.args.foo])
        command.extend(["--bar", self.args.bar])
 
        ## This specifically added in parser if the script is being called from GUI
        ## This doesn't show up when done main --help
        command.extend(["--GUI"])

        sys.argv = command
        stream = EmittingStream()
        sys.stdout = stream  # This is what I beleive is Not good, But this work
        stream.textWritten.connect(self.showOuput)
        stream.progress.connect(self.setProgress)

        analysis_thread = threading.Thread(target=main())
        analysis_thread.start()

    # Setting sys.stdout back to default
    def __del__(self):
        sys.stdout = sys.__stdout__

def gui():
    app = QApplication(sys.argv)
    window = GUI()
    window.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    gui()

我能够利用打印函数的引擎盖,它调用sys.stdout.write函数,该函数在EmittingStream中覆盖了它。 因此,每当在 main.py 中调用 print 时,它都会向 GUI 发送一个信号,然后我更新字段中的文本。

这很好用,所以我不再碰它了。 但是,困扰我的是更改 sys 变量来执行此操作。

这不是将 sys.stdout 作为参数传递给进程的重复,但确实给了我关于更改 sys.stdout 的想法

python-3.x python-多线程 系统 pyside6

评论

0赞 mahkitah 8/20/2023
我会将该模块用于所有输出。GUI 和 CLI。在这里,您可以看到如何获取日志记录输出以显示在 GUI 中: stackoverflow.com/questions/54643280/...logging
2赞 musicamante 8/20/2023
是什么让你认为改变会很糟糕?它绝对没有错,它很常见,被认为是传统的和完全标准的。sys.stdout
0赞 ABD 10/5/2023
我认为当 sys 被更改时,当时运行的任何其他 Python 模块也会将其输出定向到更新的 sys.stdout。但是,我对此进行了测试,但事实并非如此,不知何故,每个系统都有一个新的实例。与它相关的 stdout!python some_file.py

答: 暂无答案