python - 在单线程 Python 脚本中有一个控制台

标签 python multithreading console interactive

我想在一个打开了多个 TCP 连接的单线程脚本中有一个交互式控制台。这意味着我不能只让标准输入阻塞线程。

有没有简单的方法来做到这一点?还是我应该将控制台放在它自己的线程中并完成它?

最佳答案

您可以子类化 InteractiveConsole(来自内置的“代码”模块)和 使用重定向 stdout/stderr 的包装器覆盖 push() 方法 在转发到基础之前到 StringIO 实例 InteractiveConsole 的 push() 方法。你的包装器可以返回一个二元组 (more, result) 其中 'more' 表示 InteractiveConsole 是否期望 更多输入,“结果”是 InteractiveConsole.push() 写入的内容 你的 StringIO 实例。

听起来比实际更难。这是基本前提:

import sys
from cStringIO import StringIO
from code import InteractiveConsole
from contextlib import contextmanager

__all__ = ['Interpreter']


@contextmanager
def std_redirector(stdin=sys.stdin, stdout=sys.stdin, stderr=sys.stderr):
    """Temporarily redirect stdin/stdout/stderr"""

    tmp_fds = stdin, stdout, stderr
    orig_fds = sys.stdin, sys.stdout, sys.stderr
    sys.stdin, sys.stdout, sys.stderr = tmp_fds
    yield
    sys.stdin, sys.stdout, sys.stderr = orig_fds


class Interpreter(InteractiveConsole):
    """Remote-friendly InteractiveConsole subclass

    This class behaves just like InteractiveConsole, except that it
    returns all output as a string rather than emitting to stdout/stderr

    """
    banner = ("Python %s\n%s\n" % (sys.version, sys.platform) +
              'Type "help", "copyright", "credits" or "license" '
              'for more information.\n')

    ps1 = getattr(sys, "ps1", ">>> ")
    ps2 = getattr(sys, "ps2", "... ")


    def __init__(self, locals=None):
        InteractiveConsole.__init__(self, locals=locals)
        self.output = StringIO()
        self.output = StringIO()

    def push(self, command):
        """Return the result of executing `command`

        This function temporarily redirects stdout/stderr and then simply
        forwards to the base class's push() method.  It returns a 2-tuple
        (more, result) where `more` is a boolean indicating whether the
        interpreter expects more input [similar to the base class push()], and
        `result` is the captured output (if any) from running `command`.

        """
        self.output.reset()
        self.output.truncate()
        with std_redirector(stdout=self.output, stderr=self.output):
            try:
                more = InteractiveConsole.push(self, command)
                result = self.output.getvalue()
            except (SyntaxError, OverflowError):
                pass
            return more, result

查看这个完整的示例,它接受来自 UDP 套接字的输入:

启动两个控制台,其中一个运行server.py,另一个运行client.py。 你在 client.py 中看到的应该与 python 没有区别 常规交互式解释器,即使所有命令都在 往返于 server.py 进行评估。

当然,像这样使用套接字是非常不安全的,但它 说明如何异步评估外部输入。你 应该能够适应你的情况,只要你相信 输入源。当有人输入时,事情会变得“有趣”:

while True: continue

但这完全是另一个问题... :-)

关于python - 在单线程 Python 脚本中有一个控制台,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4241234/

相关文章:

c++ - 你能把 std::recursive_mutex 和 std::condition_variable 结合起来吗?

java - 当线程在 Java 中死亡时 ThreadPoolExecutor 会发生什么

c# - 如何在控制台应用程序中将文本居中?

python - python 查找具有相似列的两个表之间缺失的数据

c# - 循环的不同行为

python - pandas 绘图 - 多个颜色条

android - Google Play控制台: “impossible to specify a price in BRL for Brazil” =>无法保存修改

google-chrome - Chrome 调试器 : clicking exception link in console opens file in new tab instead of cross-linking into source file

python - 如何导入作为命令行参数提供的另一个 python 文件?

python - 创建用于数据框的函数