附录B封面

第 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      # 每次执行前自动重载所有模块的修改

一行配置,从此「改代码 → 重跑」零摩擦。

🧭 代码设计建议与配置

书尾给的两条工程心法值得抄在墙上:

  1. 交互式探索,模块化沉淀:在 notebook 里探索出可靠逻辑后,把稳定部分移进 .py 模块,用 %run/import 复用——笔记本是草稿纸,模块是成品库;
  2. 保持函数粒度小:单行能测、单函数能 profile,调试和剖析才有抓手。

最后,配置文件 ipython_config.pyipython profile create 生成)可以持久化你的偏好:配色、自动加载扩展、启动脚本。花十分钟配一次,受用所有会话。

📌 本章小结:%run 跑完脚本变量留在现场;__N 引用历史输出;! 命令 + 输出捕获让 IPython 化身 shell;崩溃后 %debug 直接穿越现场;性能优化走「%timeit%prun%lprun」三段式;%autoreload 2 让模块开发零摩擦。