模仿 Python shell 的 "return value" 行为

Emulate Python shell's "return value" behaviour

假设我有一个 JSON 列表 Python 字符串要评估。例如,也许我正在构建一个客户端-服务器 Python GUI。

常规 Python 解释器的一个方便之处在于它显示每一行的 "pseudo-return value",如下所示:

 $ python3 -c "import code; code.interact()"
 Python 3.7.7 (default, Mar 10 2020, 15:43:03) 
 (InteractiveConsole)
 >>> import os; os.curdir
 '.'

我不必要求打印出“.”。它刚刚做到了。

在幕后,可以看出这是用 exec() 函数实现的:

https://github.com/python/cpython/blob/800a35c623bbcdb5793c7d7a4974524286311479/Lib/code.py#L90

    try:
        exec(code, self.locals)
    except SystemExit:
        raise
    except:
        self.showtraceback()

奇怪的是那里没有明确的指令来输出 exec() 的结果。然而我们可以看到它确实输出了它。

我们可以看到这种行为是非常特定于上下文的,如下所示:

$ echo "5" | python3 -c "import code; code.interact()"
Python 3.7.7 (default, Mar 10 2020, 15:43:03) 
(InteractiveConsole)
>>> 5
>>> 
now exiting InteractiveConsole...
enter code here

我假设如果我深入研究 C 代码,我会发现它正在查询其上下文以确定是否输出值。但它不会回答我的主要问题,即如何在任意上下文中模拟此行为。

我怎样才能执行并从 Python 字符串中获取 "pseudo-return value",而不管该字符串表示表达式还是语句?

Python 编译器有一个 flag to keep track of whether Python is being run in interactive mode

如果设置了这个标志,当编译器访问AST中的语句节点时,它emits an extra PRINT_EXPR opcode

口译员executes PRINT_EXPR by popping the result of the expression off the stack and passing it as an argument to sys.displayhook。 displayhook 将此值的 repr 打印到标准输出,除非该值是 None。它还将值分配给 builtins._.

(我想当您将命令通过管道传输到 Python 时行为不同的原因是它不处于交互模式。)

所以只要你是 运行 Python 交互模式,你就可以在 运行 代码之后读取 _ 内置函数的值 exec内置。