第 2 章只讲了 IPython 的基本盘,附录 B 把隐藏关卡全部打开:终端操作、调试、性能剖析、自动重载。这些技巧不改变你能做什么,但深刻改变你干活的速度。
📥 代码进出的各种姿势
%run 的隐藏能力:不只是执行脚本——脚本跑完后,里面的变量、函数全部留在当前命名空间,你可以继续交互式探索。加 -i 还能共享当前会话的变量(脚本像个函数一样「吃到」现场数据)。
剪贴板直接跑:
%paste # 粘贴剪贴板代码块执行(自动处理缩进和空行)
%cpaste # 打开一个"继续粘贴"模式,避免自动立即执行
输入输出有名字:IPython 会记住你每个 cell 的输入输出:
In [5]: 2 ** 27
Out[5]: 134217728
_ # 上一个输出
__ # 上上个输出
_5 # 第 5 个 cell 的输出(Out[5])
_i5 # 第 5 个 cell 的输入字符串
%hist 翻历史,Ctrl+R 搜索历史(和 shell 一样)——「刚才那条命令怎么写的来着」从此不再是问题。
🐚 IPython 就是半个操作系统
在 IPython 里直接敲 shell 命令(前面加 !):
!ls / data # 查看目录
!python script.py args # 调外部程序
foo = !ls # 输出捕获进 Python 变量!
%cd data / %bookmark data_dir / %dhist # 目录书签系统
%bookmark 是被严重低估的功能:给深层目录起名字,%cd data_dir 直达——数据分析常在七八层目录里钻来钻去,书签能救命。
🐞 调试器:%debug 的事后诸葛亮
报错之后不要慌,一行 %debug 直接穿越到崩溃现场:
In [1]: run buggy_script.py
... ZeroDivisionError: division by zero
In [2]: %debug # 进入事后调试器
> <ipython>(3)f() # 停在出错的那一帧
ipdb> u # up:跳到上一帧看是谁调的
ipdb> p x # print 变量
ipdb> q # 退出
进入调试器后的常用指令:u/d 上下帧、p 打印、step/next 单步、q 退出。也可以用 %run -d script.py 从头单步调试,或在代码里写 set_trace() 设置断点。
⏱️ 性能剖析三件套
%time f(x) # 单次执行耗时
%timeit f(x) # 多次循环取平均(更准,自动选循环次数)
# 函数级剖析:谁最耗时、调用多少次
%prun -l 7 f(x) # 按耗时排序列出 top 函数
# 逐行剖析:函数内部每一行各花多久
%lprun -f compute_loop compute_loop(1000) # 需要 pip install line_profiler
书里的建议很实在:先用 %timeit 感知,再用 %prun 找热点函数,最后 %lprun 定位行——不要一上来就猜瓶颈,猜几乎总是错的。
🔁 模块自动重载
开发自己的模块时最烦的事:改了 .py,会话里的旧版本还在跑。
%load_ext autoreload
%autoreload 2 # 每次执行前自动重载所有模块的修改
一行配置,从此「改代码 → 重跑」零摩擦。
🧭 代码设计建议与配置
书尾给的两条工程心法值得抄在墙上:
- 交互式探索,模块化沉淀:在 notebook 里探索出可靠逻辑后,把稳定部分移进
.py模块,用%run/import 复用——笔记本是草稿纸,模块是成品库; - 保持函数粒度小:单行能测、单函数能 profile,调试和剖析才有抓手。
最后,配置文件 ipython_config.py(ipython profile create 生成)可以持久化你的偏好:配色、自动加载扩展、启动脚本。花十分钟配一次,受用所有会话。
📌 本章小结:
%run跑完脚本变量留在现场;_与_N引用历史输出;!命令 + 输出捕获让 IPython 化身 shell;崩溃后%debug直接穿越现场;性能优化走「%timeit→%prun→%lprun」三段式;%autoreload 2让模块开发零摩擦。