重要
本文档涵盖 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