重要

本文档涵盖 IPython 6.0 及更高版本。从 6.0 版本开始,IPython 不再支持与低于 Python 3.3 的 Python 版本(包括所有版本的 Python 2.7)的兼容性。

如果你正在寻找与 Python 2.7 兼容的 IPython 版本,请使用 IPython 5.x LTS 版本并参阅其文档(LTS 是长期支持版本)。

自定义输入转换

IPython 扩展了 Python 语法,以允许魔术命令等内容,并帮助使用 ? 语法。有几种方法可以自定义如何将用户的输入处理成要执行的 Python 代码。

这些钩子主要用于其他项目,它们使用 IPython 作为其交互式界面的核心。不加注意地使用它们很容易破坏 IPython!

基于字符串的转换

当用户输入代码时,它首先作为字符串进行处理。在此阶段结束时,它必须是有效的 Python 语法。

在 7.0 版本中更改:基于字符串和令牌的转换的 API 已完全重新设计。任何扩展输入转换的第三方代码都需要重写。希望新的 API 更简单。

基于字符串的转换是接受字符串列表的函数:每个字符串都是输入单元格的单行,包括其行尾。转换函数应以相同的结构返回输出。

这些转换分为两组,可作为 InteractiveShell 实例的属性访问。每组都是一个转换函数列表。

  • input_transformers_cleanup 首先在输入上运行,以执行诸如从复制的代码中删除提示和前导缩进之类的操作。在此阶段,可能无法将输入解析为有效的 Python 代码。

  • 然后,IPython 运行自己的转换来处理其特殊语法,例如 %magics!system 命令。此部分不公开扩展点。

  • input_transformers_post 作为最后一步运行,以执行诸如将浮点字面量转换为十进制对象之类的操作。这些操作可能会尝试将输入解析为 Python 代码。

如果输入代码无效,这些转换器可能会引发SyntaxError,但在大多数情况下,将未识别的代码原样传递并让 Python 自己的解析器决定它是否有效会更清晰。

例如,假设我们想通过反转每一行来混淆我们的代码,因此我们将编写)5(f =+ a而不是a += f(5)。以下是如何在 IPython 尝试运行它之前将其交换回正确的方式

def reverse_line_chars(lines):
    new_lines = []
    for line in lines:
        chars = line[:-1]  # the newline needs to stay at the end
        new_lines.append(chars[::-1] + '\n')
    return new_lines

要开始使用此功能

ip = get_ipython()
ip.input_transformers_cleanup.append(reverse_line_chars)

在版本 7.17 中添加: input_transformers 现在可以具有一个属性has_side_effects,设置为True,这将阻止在 IPython 尝试猜测用户输入是否完整时运行转换器。

AST 转换

在代码被解析为 Python 语法后,你可以使用 Python 强大的抽象语法树工具对其进行修改。子类ast.NodeTransformer,并将一个实例添加到shell.ast_transformers

此示例将整数文字包装在一个Integer类中,这对于希望处理例如1/3作为精确分数的数学框架很有用

class IntegerWrapper(ast.NodeTransformer):
    """Wraps all integers in a call to Integer()"""
    def visit_Num(self, node):
        if isinstance(node.n, int):
            return ast.Call(func=ast.Name(id='Integer', ctx=ast.Load()),
                            args=[node], keywords=[])
        return node