IPython 是 Python 的交互式外壳,装完用 ipython 命令进。Tab 补全从这里开始有用。 三个前缀是三把钥匙:名字加问号查文档,% 开头跑魔法命令,! 开头调系统命令。 三把都不属于 Python 语言,都是外壳提供的便利——离开 IPython 就不存在。
上一篇讲 Notebook 这个壳,这一篇讲壳下面的 IPython。两者是同一套东西的两种界面。 本沙箱装了 IPython 9.18.0,文中的三把钥匙都是脚本里真跑出来的输出。
一、装上、进去、写第一句
装:python -m pip install ipython。装完命令行敲 ipython 就进去了。 进去之后提示符变成 In [1]:。敲一行,回车就出结果,不用建文件。 这就是交互式的价值:试一个想法,从想到看到只要一秒。
退出用 exit 或 Ctrl+D。Tab 补全是这个环境最常用的功能,打完前几个字母按 Tab。
二、第一把:问号查文档
名字后面加一个问号,打印签名和文档;加两个问号,连源码一起打。
比如 len?,输出三行:Signature: len(obj, /)、
Docstring: Return the number of items in a container.、Type: builtin_function_or_method。
签名那一行的 / 表示后面的参数只能按位置传,不能写 len(obj=...) 这种。
这一个动作省掉的查文档时间,比任何插件都多。
三、第二把:百分号跑魔法命令
以 % 开头的是魔法命令,是 IPython 自己实现的快捷方式,不是 Python 语法。
| 命令 | 作用 |
|---|---|
| %timeit | 测一行代码跑多久,自动决定跑几次 |
| %run | 跑一个 .py 文件,变量留在当前会话里 |
| %who | 列出当前定义了哪些变量 |
| %pwd / %cd | 看和切换工作目录 |
| %matplotlib inline | 让图直接显示在页面里(Notebook 专用) |
最常用的是 %timeit。 本篇实测一次 sum(range(1000)),输出形如 18.5 us ± 0 ns per loop——具体时间每次都不一样。 魔法命令只在 IPython 和 Notebook 里有效。存成 .py 用 python 跑,% 那行会报语法错。
四、第三把:叹号调系统命令
以 ! 开头的行,直接交给操作系统执行,输出当成字符串返回。 跑 !echo hello-from-shell,拿到 hello-from-shell。 还能把结果接回来:files = !dir 之后,files 就是一个列表,可以继续用 Python 处理。
这一把让 Notebook 里能顺手做 shell 的事:看目录、解压、调 git,不用来回切窗口。 别拿它跑危险命令。!rm 是真删,没有回收站,也没有撤销。
五、三把钥匙的共同点
都不属于 Python 语言,都是 IPython 这个壳提供的便利。 换句话说:离开 IPython,这三样都不存在;离开 Python,IPython 也不存在。 分清「语言的语法」和「工具的便利」,就不会把 %timeit 写进正式脚本然后纳闷为什么报错。
本沙箱怎么用:没装 Jupyter,但装了 IPython,用 InteractiveShell 对象在脚本里跑这三把钥匙。 机制是同一个。
六、动手 Demo:IPython 的三把钥匙
用 InteractiveShell 在脚本里模拟交互式会话,分别试问号、% 和 ! 三种前缀。 捕获它们的输出打出来——注意时间类的输出每次都不一样。
from IPython.core.interactiveshell import InteractiveShell
from IPython.utils.capture import capture_output
sh = InteractiveShell.instance()
with capture_output() as cap:
sh.run_cell("len?")
print("[问号]")
for line in cap.stdout.strip().split(chr(10))[:4]:
print(" " + line)
with capture_output() as cap:
sh.run_line_magic("timeit", "-n 100 -r 3 sum(range(1000))")
print("[百分号] %s" % cap.stdout.strip())
with capture_output() as cap:
sh.run_cell("!echo hello-from-shell")
print("[叹号] %s" % cap.stdout.strip())
实跑输出:
--------------------------------------------------------------------
IPython 的三把钥匙
--------------------------------------------------------------------
① 第一把:问号查文档
--------------------------------------------------------------------
在名字后面加一个问号,打印它的签名和文档;加两个问号,连源码一起打。
比如 len? 的输出是这样的:
[31mSignature:[39m len(obj, /)
[31mDocstring:[39m Return the number of items in a container.
[31mType:[39m builtin_function_or_method
! 这一个动作省掉的查文档时间,比任何插件都多。
② 第二把:百分号跑魔法命令
--------------------------------------------------------------------
以 % 开头的是「魔法命令」,是 IPython 自己实现的快捷方式,不是 Python 语法。
| 命令 | 作用 | 频率 |
|---|---|---|
| %timeit | 测一行代码跑多久 | 常用 |
| %run | 跑一个 .py 文件 | 常用 |
| %who | 列出当前定义的变量 | 常用 |
| %pwd / %cd | 看和切换工作目录 | 常用 |
| %matplotlib inline | 让图直接显示在页面里 | 画图时用 |
实测一条 %timeit(时间每次都变,只作形式示例):
16.8 us +- 1.71 us per loop (mean +- std. dev. of 3 runs, 100 loops each)
! 魔法命令只在 IPython 和 Notebook 里有效。存成 .py 用 python 跑,% 那行会报语法错。
③ 第三把:叹号调系统命令
--------------------------------------------------------------------
以 ! 开头的行,直接交给操作系统执行,输出当成字符串返回。
跑 !echo hello-from-shell,拿到:hello-from-shell
还能把结果接回来用:files = !dir 之后,files 就是一个列表。
! 这一把让 Notebook 里能顺手做 shell 的事:看目录、解压、调 git,不用来回切窗口。
④ 三把钥匙共同点
--------------------------------------------------------------------
都不属于 Python 语言,都是 IPython 这个壳提供的便利。
换句话说:离开 IPython,这三样都不存在;离开 Python,IPython 也不存在。
! 分清「语言的语法」和「工具的便利」,就不会把 %timeit 写进正式脚本然后纳闷为什么报错。
⑤ 本沙箱怎么用这三把钥匙
--------------------------------------------------------------------
这台机器没装 Jupyter,但装了 IPython 9.18.0。上面三段都是脚本里真跑出来的。
机制是同一个:InteractiveShell 对象负责解释 ?、% 和 ! 这三种前缀。
! 平台原样标一句:教材里的 Jupyter 页面交互本沙箱不执行,等价能力已用 IPython 复刻。
capture_output 是 IPython 自带的输出捕获器,专门用来在脚本里拿交互式的输出。
%timeit 那一行的时间每次都不一样,所以正文里从不写死具体数字,只写它长什么样。
30 秒实验
- 试试 str.replace?,看它的签名里有几个参数。
- 用 %run 跑一个写好的 .py 文件,再在会话里打 %who 看变量名。
- 想一想:为什么 %timeit 要跑很多次再取平均,而不是只跑一次?
常见误区
- 把魔法命令写进 .py 文件:那不是 Python 语法,用 python 跑直接报错。
- 拿 ! 跑删除命令:没有回收站,删了就没了。
- 只看文档不看签名:文档讲用途,签名讲怎么调用,两个都要看。
- timeit 结果当基准数据:它受机器、负载、缓存影响,只能跟自己比。
自测三问(点开对答案)
1. 问号、百分号、叹号三种前缀,分别是谁提供的? —— 都是 IPython 这个外壳提供的,不是 Python 语言的语法。 2. 为什么 %timeit 的输出不能写死在文章里? —— 因为它依赖机器、当前负载和缓存状态,每次跑都不一样。 3. !echo 和 print 有什么区别? —— !echo 调的是操作系统的 echo 程序,print 是 Python 的函数。前者输出能被当字符串接回来。三把钥匙是入口。真正让人学得快的是下一层:不看文档也能问出「它能干什么」。下一篇讲内省。
- ☐ (本篇完,下一篇 2.8 IPython 进阶:内省、魔法命令、调 Shell)