覆盖 REPL 输出
Override REPL output
我正在寻找一种方法来覆盖和解析 Python REPL 中的所有输出:例如 python/IPython 在终端中,qtconsole。
这对于打印文本来说很简单,只需覆盖打印功能即可。举一个简单的例子,假设我们想在所有输出中添加一个感叹号:
orig_print = print
print = lambda text: orig_print(text + '!')
现在所有打印命令都将添加感叹号。这可以通过以下方式重置:
del print
我的问题:如何为 REPL 输出执行等效操作?例如,我怎样才能做到这一点?
In[1]: 5 + 5
Out[2]: 10!
搜索让我找到了上下文库、子进程和 sys.stdout,但我还没有找到解决方案。在 Github 检查了 sympy 的打印模块,但没有成功。
我刚刚尝试覆盖 sys.stdout.write
并且成功了(有一些问题)。如果我错了,有人会纠正我,但我认为它不会比这更好。
In [1]: import sys
In [2]: tmp = sys.stdout.write
In [3]: sys.stdout.write = lambda text: tmp(text + '!')
In [4]: 5 + 5
!Out[4]: 10!
!!
!!In [5]:
编辑:
我已经走到这一步了。还没弄清楚那 1 个额外的 !
来自哪里。
In [5]: sys.stdout.write = lambda text: tmp(text if text.endswith('\n') else text + '!\r')
In [6]: 5+5
Out[6]: 10!
!
In [7]:
一个在 IPython QtConsole 中工作的示例,基于 this article。这与 orangeink 覆盖标准输出的解决方案结合使用:
class SciNum:
"""For compatibility with IPython's pretty printer: Contains a string,
with a REPR that allows pretty() to print without quotes, as it would
if using the string directly."""
def __init__(self, text: str):
self.text = text
def __repr__(self):
return self.text
def _print_ipython(arg, p, cycle) -> None:
"""Uses IPython's pretty printer to modify output for a qtconsole or notebook;
stdout doesn't seem to work for them."""
p.text(IPython.lib.pretty.pretty(SciNum(format(arg))))
def start() -> None:
if not ipython_exists:
return
ip = IPython.get_ipython()
# We only need to handle IPython separately if in a Qtconsole or Notebook.
if isinstance(ip, IPython.terminal.interactiveshell.TerminalInteractiveShell):
return
text_formatter = ip.display_formatter.formatters['text/plain']
text_formatter.for_type(float, _print_ipython)
text_formatter.for_type(int, _print_ipython)
标准 REPL 调用 sys.displayhook
来完成它的工作:https://docs.python.org/3/library/sys.html#sys.displayhook
简单示例:
>>> import sys
>>> def displayhook(value):
... if value is None: return
... sys.stdout.write(repr(value) + "!\n")
...
>>> sys.displayhook = displayhook
>>> 1 + 1
2!
请注意,这不适用于 ipython,但它适用于默认的 REPL(您通常只需调用 python3
即可获得)以及 IDLE(python3 -m idlelib.idle
).
我正在寻找一种方法来覆盖和解析 Python REPL 中的所有输出:例如 python/IPython 在终端中,qtconsole。
这对于打印文本来说很简单,只需覆盖打印功能即可。举一个简单的例子,假设我们想在所有输出中添加一个感叹号:
orig_print = print
print = lambda text: orig_print(text + '!')
现在所有打印命令都将添加感叹号。这可以通过以下方式重置:
del print
我的问题:如何为 REPL 输出执行等效操作?例如,我怎样才能做到这一点?
In[1]: 5 + 5
Out[2]: 10!
搜索让我找到了上下文库、子进程和 sys.stdout,但我还没有找到解决方案。在 Github 检查了 sympy 的打印模块,但没有成功。
我刚刚尝试覆盖 sys.stdout.write
并且成功了(有一些问题)。如果我错了,有人会纠正我,但我认为它不会比这更好。
In [1]: import sys
In [2]: tmp = sys.stdout.write
In [3]: sys.stdout.write = lambda text: tmp(text + '!')
In [4]: 5 + 5
!Out[4]: 10!
!!
!!In [5]:
编辑:
我已经走到这一步了。还没弄清楚那 1 个额外的 !
来自哪里。
In [5]: sys.stdout.write = lambda text: tmp(text if text.endswith('\n') else text + '!\r')
In [6]: 5+5
Out[6]: 10!
!
In [7]:
一个在 IPython QtConsole 中工作的示例,基于 this article。这与 orangeink 覆盖标准输出的解决方案结合使用:
class SciNum:
"""For compatibility with IPython's pretty printer: Contains a string,
with a REPR that allows pretty() to print without quotes, as it would
if using the string directly."""
def __init__(self, text: str):
self.text = text
def __repr__(self):
return self.text
def _print_ipython(arg, p, cycle) -> None:
"""Uses IPython's pretty printer to modify output for a qtconsole or notebook;
stdout doesn't seem to work for them."""
p.text(IPython.lib.pretty.pretty(SciNum(format(arg))))
def start() -> None:
if not ipython_exists:
return
ip = IPython.get_ipython()
# We only need to handle IPython separately if in a Qtconsole or Notebook.
if isinstance(ip, IPython.terminal.interactiveshell.TerminalInteractiveShell):
return
text_formatter = ip.display_formatter.formatters['text/plain']
text_formatter.for_type(float, _print_ipython)
text_formatter.for_type(int, _print_ipython)
标准 REPL 调用 sys.displayhook
来完成它的工作:https://docs.python.org/3/library/sys.html#sys.displayhook
简单示例:
>>> import sys
>>> def displayhook(value):
... if value is None: return
... sys.stdout.write(repr(value) + "!\n")
...
>>> sys.displayhook = displayhook
>>> 1 + 1
2!
请注意,这不适用于 ipython,但它适用于默认的 REPL(您通常只需调用 python3
即可获得)以及 IDLE(python3 -m idlelib.idle
).