14. 交互式输入编辑与历史记录
对应官方文档:14. Interactive Input Editing and History Substitution 一句话导读:这一章把
>>>提示符从「只能一行行重敲」升级成「能补全、能翻历史、能改当前行」,学完敲实验代码不再靠复制粘贴。
前面十二章的示例都在 >>> 后面敲。你大概已经体验过:写错一个字母得整行重敲,上一条命令想改个参数又得从头打一遍。官方第 14 章就是来解决这个的——它借了 GNU Readline 库的能力,让交互式解释器像 Bash 一样能编辑当前行、能翻历史。
你可以这样理解:REPL 是「边问边答」的白板,Readline 是给这块白板配了橡皮、撤销键和一本翻页的草稿本。
14.1 Tab 补全与历史编辑
补全是自动开的,不用手动装
官方说得很明确:补全在解释器启动时就自动启用了。Tab 键会触发补全函数,它看三样东西:当前语句里的名字、当前局部变量、以及已经导入或可导入的模块名。
底层是两个标准库模块在干活:
readline:真正负责「读一行、允许左右移动光标、上下翻历史、绑定快捷键」,是 GNU Readline(macOS 上通常是它的近亲 libedit)的 Python 封装。rlcompleter:负责「给你一串候选」,补全逻辑就在这里。
Python 3 的 site.py 在启动时把 rlcompleter 挂到 sys.__interactivehook__ 上,所以你什么都不配,进 >>> 按 Tab 就能补全。
# 不进交互模式,也能直接看补全器是怎么给候选的
import rlcompleter
c = rlcompleter.Completer()
for state in range(6):
print(state, "->", c.complete("str.", state))
print("补全 str.ca ->", c.complete("str.ca", 0))
0 -> str.capitalize(
1 -> str.casefold(
2 -> str.center(
3 -> str.count(
4 -> str.encode(
5 -> str.endswith(
补全 str.ca -> str.capitalize(
补全器也会看你自己的变量,所以变量名起得有共同前缀时特别好用:
import rlcompleter
ns = {"my_score": 98, "my_name": "村长"}
c = rlcompleter.Completer(ns)
print(c.complete("my_", 0), "|", c.complete("my_", 1), "|", c.complete("my_", 2))
my_score | my_name | None
对 string.a 这种点号表达式,补全器会先求值点号前面那段,再列出结果对象的属性。这带来一个容易被忽略的副作用:如果链路上某个对象自定义了 __getattr__(),按一下 Tab 就可能真的执行了应用代码。别在生产环境连着数据库的对象上乱按 Tab。
村长划重点:补全不是「字符串匹配」,是「求值 + 查属性」。另外平台差异要记牢:macOS 自带的是 libedit,个别 readline 配置项写法不同;Windows 默认没有
readline模块,老版本补全不可用(Python 3.13 起的新交互 shell 自带一套补全,见第 16 章附录)。
上下箭头与历史文件
↑ / ↓ 翻上一条、下一条命令,Ctrl-P / Ctrl-N 是等价的字母写法。更关键的是跨会话的历史:默认配置会把你敲过的命令存到用户目录下的 .python_history,下次开解释器还在。这也是官方说的「history will be available again during the next interactive interpreter session」。
常用快捷键村长整理成一张表,按 Emacs 风格记就行(Readline 默认就是这套):
| 快捷键 | 作用 | 记忆线索 |
|---|---|---|
Tab | 补全名字 / 属性 | complete |
↑ / Ctrl-P | 上一条历史 | previous |
↓ / Ctrl-N | 下一条历史 | next |
Ctrl-R | 反向搜索历史,边敲边找 | reverse search |
Ctrl-A | 跳到行首 | ahead / beginning |
Ctrl-E | 跳到行尾 | end |
Ctrl-B / Ctrl-F | 光标左移 / 右移一格 | backward / forward |
Ctrl-K | 删到行尾 | kill |
Ctrl-U | 删到行首 | unix line kill |
Ctrl-W | 删前一个单词 | word |
Ctrl-D | 删除光标处字符;空行时退出解释器 | delete / EOF |
Ctrl-L | 清屏 | clear |
Ctrl-C | 丢弃当前输入、回到主提示符;运行中则抛 KeyboardInterrupt | cancel |
Ctrl-R 是效率分水岭:按下后敲几个关键字,它会从最近的命令往回找,再按 Ctrl-R 继续往更早翻,回车直接执行,先按 → 或 Ctrl-E 则是「找到但先改两句再执行」。
村长划重点:章节标题里的「History Substitution」指的是 Readline 这套历史浏览机制,不是 Bash 里的
!!、!$那种历史展开——Python 的>>>默认没开这个,照搬会当成普通字符串。另外Ctrl-S正向搜索在很多终端里会被流控(XOFF)吃掉,看起来像「卡死」,先别慌,按Ctrl-Q恢复,或者干脆只用Ctrl-R。
把补全固化进启动文件(.pythonrc 与 PYTHONSTARTUP)
老版本 Python 或某些精简环境里,Tab 补全没自动开,就得自己写启动文件。约定俗成放成 ~/.pythonrc,再让环境变量 PYTHONSTARTUP 指过去。下面这份是能直接当文件用的完整配置:
# ~/.pythonrc:由 PYTHONSTARTUP 指向,只在交互模式启动时执行
import atexit
import os
try:
import readline
except ImportError:
pass # Windows 等没有 readline 的平台,跳过即可
else:
import rlcompleter
readline.parse_and_bind("tab: complete")
histfile = os.path.join(os.path.expanduser("~"), ".python_history")
try:
readline.read_history_file(histfile)
except FileNotFoundError:
pass
atexit.register(readline.write_history_file, histfile)
print("启动文件已加载:Tab 补全与历史记录就绪")
# 写进 shell 配置(~/.zshrc 或 ~/.bashrc),对每次新开的终端生效
export PYTHONSTARTUP="$HOME/.pythonrc"
# 只对当前这一次生效也行
PYTHONSTARTUP="$HOME/.pythonrc" python3
PYTHONSTARTUP 指向的文件里的 import、def 都执行在交互会话同一个命名空间,所以你在里面定义个 c = rlcompleter.Completer(),进 >>> 直接敲 c 就能用。想改提示符也可以在这里动 sys.ps1 / sys.ps2;更多细节在第 16 章的 16.1.3 展开。
14.2 交互式解释器的替代方案
官方很坦白:Readline 这套相比早年已经是巨大进步,但仍有几个愿望没实现——续行时自动提示缩进、补全用解释器符号表、检查括号引号是否配对。所以官方点名了两个增强版:IPython(Tab 补全、对象探查、高级历史、可深度定制、可嵌入别的程序)和 bpython(类似思路、界面更花哨)。
村长把常见的选项补成一张表,按「你是谁」来选就行:
| 工具 | 一句话特点 | 适合谁 |
|---|---|---|
原生 python3 | 零安装、到处都有、最贴近教程示例 | 刚入门、跟教程敲代码、服务器上临时查东西 |
| IPython | ? / ?? 查对象、%timeit 测速、%run 跑脚本、历史可跨会话检索 | 天天泡在 REPL 里做实验的人 |
| Jupyter Notebook / Lab | 代码分成单元格,图和表格原地显示,能导出成笔记 | 数据分析、教学、要给别人看过程 |
| IDLE | 标准库自带(tkinter 写的),带简单编辑器和调试器 | 不想装任何东西、需要图形界面的初学者 |
| bpython | 实时语法高亮、参数提示、自动补全列表浮在下方 | 喜欢「边打边看提示」的人 |
| ptpython | 基于 prompt_toolkit,多行编辑、Vi/Emacs 键位、可嵌入 | 想要现代终端体验、常写多行函数的人 |
| 编辑器内置交互窗口 | VS Code / PyCharm 的 Python Console,和断点调试连着 | 已经在写项目、想边调试边试表达式 |
装起来都是一行的事:
python3 -m pip install ipython jupyterlab bpython ptpython
python3 -m idlelib # IDLE 不用装,标准库自带
几个容易踩的点说清楚:
- IPython 不读
PYTHONSTARTUP。它有自己的启动目录~/.ipython/profile_default/startup/,把.py文件丢进去即可,命名建议带个数字前缀控制顺序。 - Jupyter 不是「更好用的
>>>」,它是「把代码、输出、说明混在一起的笔记本」。适合探索和展示,不适合拿来调一个几十行的脚本。 - Python 3.13 起原生解释器换了新交互 shell(彩色、多行编辑、历史浏览、粘贴模式),官方附录里专门讲了,这部分在第 16 章的 16.1 补。
- 想让某个脚本跑完后停在交互状态接着查变量,用
python3 -i script.py,不用换工具。
村长划重点:工具是分场景的,别一上来就装全套。跟教程走完前十二章之前,原生
python3最省事——它的报错、提示符、行为都和官方文档一字不差;等开始做数据分析再上 Jupyter,等天天做实验再上 IPython,迁移成本几乎为零。
本章小结
- 补全由
readline(行编辑与快捷键)+rlcompleter(生成候选)实现,Python 3 通过sys.__interactivehook__在启动时自动启用,无需手动配置。 - 点号补全会对点号前的表达式求值,可能触发自定义
__getattr__();macOS 是 libedit、Windows 默认无readline,存在平台差异。 - 默认把历史存进
~/.python_history,下次会话还在;↑/Ctrl-P翻历史,Ctrl-R反向搜索,配合Ctrl-A/E/K/U/W改当前行。 - 章节标题的「历史替换」指 Readline 的历史浏览,不是 Bash 的
!!展开;Ctrl-S可能被终端流控拦截,用Ctrl-Q恢复。 - 用
PYTHONSTARTUP指向~/.pythonrc可固化补全和历史;IPython 用自己的 startup 目录。替代工具按场景选:Jupyter 做分析、IDLE 图省事、bpython / ptpython 追求终端体验。