重要
本文档涵盖 IPython 6.0 及更高版本。从 6.0 版本开始,IPython 不再支持与低于 Python 3.3 的 Python 版本(包括所有版本的 Python 2.7)的兼容性。
如果您正在寻找与 Python 2.7 兼容的 IPython 版本,请使用 IPython 5.x LTS 版本并参阅其文档(LTS 是长期支持版本)。
与 GUI 事件循环集成¶
当用户键入 %gui qt
时,IPython 会将自身与 Qt 事件循环集成,以便您可以同时使用 GUI 和交互式提示符。IPython 支持许多常见的 GUI 工具包,但从 IPython 3.0 开始,可以在不修改 IPython 本身的情况下集成其他事件循环。
支持的事件循环包括 qt5
、qt6
、gtk2
、gtk3
、gtk4
、wx
、osx
和 tk
。确保您指定的事件循环与您自己的代码使用的 GUI 工具包匹配。
要使 IPython GUI 事件循环集成在每次启动时自动发生,请在您的 IPython 配置文件中设置 c.InteractiveShellApp.gui
配置键(请参阅 设置可配置选项)。
如果您使用的事件循环受 IPython 支持,无论您使用终端 IPython 还是 IPython 内核,启用事件循环集成都遵循刚才描述的步骤。
但是,终端 IPython 处理事件循环的方式与 IPython 内核处理事件循环的方式非常不同,因此如果您需要与新型事件循环集成,则需要不同的步骤来与每个事件循环集成。
在终端中与新事件循环集成¶
版本 5.0 中已更改:有一个新的 API 用于使用 prompt_toolkit 集成事件循环。
在终端中,IPython 使用 prompt_toolkit 向用户提示输入。prompt_toolkit 提供了与外部事件循环集成的钩子。
要集成事件循环,请定义一个函数,该函数运行 GUI 事件循环,直到有输入等待 prompt_toolkit 处理。有两种方法可以检测此条件
# Polling for input.
def inputhook(context):
while not context.input_is_ready():
# Replace this with the appropriate call for the event loop:
iterate_loop_once()
# Using a file descriptor to notify the event loop to stop.
def inputhook2(context):
fd = context.fileno()
# Replace the functions below with those for the event loop.
add_file_reader(fd, callback=stop_the_loop)
run_the_loop()
定义此函数后,使用 IPython 注册该函数
- IPython.terminal.pt_inputhooks.register(name, inputhook)¶
将函数 inputhook 注册为 GUI name 的事件循环集成。如果
name='foo'
,那么用户可以通过运行%gui foo
来启用此集成。
在内核中与新的事件循环集成¶
内核运行自己的事件循环,因此与其他事件循环集成更简单。IPython 允许其他事件循环进行控制,但它必须定期调用 IPython.kernel.zmq.kernelbase.Kernel.do_one_iteration()
。
要与此集成,请编写一个函数,该函数采用一个参数(IPython 内核实例),安排事件循环调用 kernel.do_one_iteration()
,至少每 kernel._poll_interval
秒调用一次,并启动事件循环。
使用 IPython.kernel.zmq.eventloops.register_integration()
装饰此函数,传入要为其注册的名称。以下是 IPython 中已包含的 Tkinter 集成的略微简化版本
@register_integration('tk')
def loop_tk(kernel):
"""Start a kernel with the Tk event loop."""
from tkinter import Tk
# Tk uses milliseconds
poll_interval = int(1000*kernel._poll_interval)
# For Tkinter, we create a Tk object and call its withdraw method.
class Timer(object):
def __init__(self, func):
self.app = Tk()
self.app.withdraw()
self.func = func
def on_timer(self):
self.func()
self.app.after(poll_interval, self.on_timer)
def start(self):
self.on_timer() # Call it once to get things going.
self.app.mainloop()
kernel.timer = Timer(kernel.do_one_iteration)
kernel.timer.start()
一些事件循环可以做得更好,并集成对内核的 ZMQ 套接字上的消息的检查,从而使内核比普通轮询更具响应性。如何执行此操作超出了本文档的范围;如果您有兴趣,请查看 IPython.kernel.zmq.eventloops
中 Qt 的集成。