内省
在变量的前面或后面加上一个问号(?)就可以将有关该对象的一些通用信息显示出来:
- In [545]: b?
- Type: list
- String Form:[1, 2, 3]
- Length: 3
- Docstring:
- list() -> new empty list
- list(iterable) -> new list initialized from iterable's items
这就叫做对象内省(object introspection)译注5。如果该对象是一个函数或实例方法,则其docstring(如果有的话)也会被显示出来:
- def add_numbers(a, b):
- """
- Add two numbers together
- Returns
- -------
- the_sum : type of arguments
- """
- return a + b
然后可以利用?来显示这段docstring:
- In [547]: add_numbers?
- Type: function
- String Form:<function add_numbers at 0x5fad848>
- File: book_scripts/<ipython-input-546-5473012eeb65>
- Definition: add_numbers(a, b)
- Docstring:
- Add two numbers together
- Returns
- -------
- the_sum : type of arguments
使用??还将显示出该函数的源代码(如果可能的话):
- In [548]: add_numbers??
- Type: function
- String Form:<function add_numbers at 0x5fad848>
- File: book_scripts/<ipython-input-546-5473012eeb65>
- Definition: add_numbers(a, b)
- Source:
- def add_numbers(a, b):
- """
- Add two numbers together
- Returns
- -------
- the_sum : type of arguments
- """
- return a + b
?还有一个用法,即搜索IPython命名空间,类似于标准UNIX或Windows命令行中的那种用法。一些字符再配以通配符(*)即可显示出所有与该通配符表达式相匹配的名称。例如,我们可以列出NumPy顶级命名空间中含有"load"的所有函数:
- In [549]: np.*load*?
- np.load
- np.loads
- np.loadtxt
- np.pkgload
%run命令
在IPython会话环境中,所有文件都可以通过%run命令当做Python程序来运行。假设你在ipython_script_test.py中存放了一段简单的脚本,如下所示:
- def f(x, y, z):
- return (x + y) / z
- a = 5
- b = 6
- c = 7.5
- result = f(a, b, c)
只要将文件名传给%run就可以运行了:
- In [550]: %run ipython_script_test.py译注6
脚本是在一个空的命名空间中运行的(没有任何import,也没有定义任何其他的变量),所以其行为应该跟在标准命令行环境(通过python script.py启动的)中执行时一样。此后,该文件中所定义的全部变量(还有各种import、函数和全局变量)就可以在当前IPython shell中访问了(除非发生了异常):
- In [551]: c
- Out[551]: 7.5
- In [552]: result
- Out[552]: 1.4666666666666666
如果Python脚本需要用到命令行参数(通过sys.argv访问),可以将参数放到文件路径的后面,就像在命令行上执行那样。
注意: 如果希望脚本能够访问在交互式IPython命名空间译注7中定义的变量,那就应该使用%run i而不是%run。
中断正在执行的代码
任何代码在执行时(无论是通过%run执行的脚本,还是长时间运行的命令),只要按下"Ctrl-C",就会引发一个KeyboardInterrupt。除一些非常特殊的情况之外,绝大部分Python程序都将立即停止执行。
警告: 当Python代码已经调用了某个已编译的扩展模块时,按下"Ctrl-C"将无法使程序立即停止执行。在这种情况下,要么只能等待Python解释器重新获得控制权,要么只能通过操作系统的任务管理器强制终止Python进程(比较极端的情况下才需要这么干)。
执行剪贴板中的代码
在IPython中执行代码的最简单方式是粘贴剪贴板中的代码。虽然这种做法很粗糙,但在实际工作中却很有用。比如说,在开发一个复杂或费时的应用程序时,你可能希望能一段一段地执行脚本,以便查看各个阶段所加载的数据以及产生的结果。又比如说,你在网上找了一段合用的代码,但又不想专门为其新建一个.py文件。
多数情况下,我们都可以通过"Ctrl-Shift-V"将剪贴板中的代码片段粘贴出来译注8。注意,这并不是万试万灵的,因为这种粘贴方式模拟的是在IPython中逐行输入代码,换行符会被处理为<return>。也就是说,如果你所粘贴的是一段缩进代码,且其中有一个空行,IPython就会认为缩进在空行那里结束了。当执行到缩进块后面那行代码时,就会引发一个IndentationError。例如下面这段代码:
- x = 5
- y = 7
- if x > 5:
- x += 1
- y = 8
直接粘贴是不行的:
- In [1]: x = 5
- In [2]: y = 7
- In [3]: if x > 5:
- ...: x += 1
- ...:
- In [4]: y = 8
- IndentationError: unexpected indent
- If you want to paste code into IPython, try the %paste and %cpaste magic functions.
正如错误提示信息所说的那样,我们应该使用%paste和%cpaste这两个魔术函数。%paste可以承载剪贴板中的一切文本译注9,并在shell中以整体形式执行译注10:
- In [6]: %paste
- x = 5
- y = 7
- if x > 5:
- x += 1
- y = 8
- ## -- End pasted text --
警告: 根据你的系统平台以及Python的安装情况,%paste可能会不起作用。EPDFree(在第1章中介绍过)等打包发布的版本应该没有问题。
%cpaste跟%paste差不多译注11,只不过它多出了一个用于粘贴代码的特殊提示符而已:
- In [7]: %cpaste
- Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
- :x = 5
- :y = 7
- :if x > 5:
- : x += 1
- :
- : y = 8
- :--
对于%cpaste块,在最终执行之前,你想粘贴多少代码就粘贴多少。如果想在执行那些粘贴进去的代码之前先检查一番,就可以考虑使用%cpaste。如果发现粘贴的代码有错,只需按下"Ctrl-C"即可终止%cpaste提示符。
后面我将会介绍IPython HTML Notebook,它使我们能以一种基于浏览器的notebook格式逐段对可执行代码单元进行分析。
IPython跟编辑器和IDE之间的交互
某些文本编辑器(如Emacs和vim)带有一些能将代码块直接发送到IPython shell的第三方扩展。详情请参考IPython网站或搜索引擎。
某些IDE(如PyDev plugin for Eclipse和Python Tools for Visual Studio(微软出品))都集成了IPython终端应用程序。如果你既想用IDE又不想放弃IPython控制台,这可能是个不错的选择。
键盘快捷键
IPython提供了许多用于提示符导航(Emacs文本编辑器或UNIX bash shell的用户对此会很熟悉)和查阅历史shell命令(详见下一节)的键盘快捷键。表3-1总结了最常用的一些快捷键。图3-1说明了几个光标移动快捷键的功能。
图3-1:几个IPython键盘快捷键的用法
译注12:这个快捷键的功能只是跟Ctrl-K相反而已,即删除从光标开始至行首的文本,并非完全删除。
异常和跟踪
如果%run某段脚本或执行某条语句时发生了异常,IPython默认会输出整个调用栈跟踪(traceback),其中还会附上调用栈各点附近的几行代码作为上下文参考。
- In [553]: %run ch03/ipython_bug.py
- In [553]: %run ch03/ipython_bug.py
AssertionError Traceback (most recent call last) /home/wesm/code/ipython/IPython/utils/py3compat.pyc in execfile(fname, *where)
176 else:
177 filename = fname
—> 178 builtin.execfile(filename, *where) book_scripts/ch03/ipython_bug.py in <module>() 13 throws_an_exception() 14 —-> 15 calling_things() book_scripts/ch03/ipython_bug.py in calling_things() 11 def calling_things(): 12 works_fine() —-> 13 throws_an_exception() 14 15 calling_things() book_scripts/ch03/ipython_bug.py in throws_an_exception() 7 a = 5 8 b = 6 ——> 9 assert(a + b == 10) 10 11 def calling_things(): AssertionError:
拥有额外的上下文代码参考是它相对于标准Python解释器的一大优势。上下文代码参考的数量可以通过%xmode魔术命令进行控制,既可以少(与标准Python解释器相同)也可以多(带有函数参数值以及其他信息)。本章稍后还会讲到如何在发生异常之后进入跟踪栈进行交互式的事后调试(post-mortem debugging)。
魔术命令
IPython有一些特殊命令(被称为魔术命令(Magic Command)),它们有的为常见任务提供便利,有的则使你能够轻松控制IPython系统的行为。魔术命令是以百分号%为前缀的命令。例如,你可以通过%timeit这个魔术命令检测任意Python语句(如矩阵乘法)的执行时间(稍后将对此进行详细讲解):
- In [554]: a = np.random.randn(100, 100)
- In [555]: %timeit np.dot(a, a)
- 10000 loops, best of 3: 69.1 us per loop
魔术命令可以看做运行于IPython系统中的命令行程序。它们大都还有一些“命令行选项”,使用?即可查看其选项:
- In [1]: %reset?
- Resets the namespace by removing all names defined by the user.
- Parameters
- ----------
- -f : force reset without asking for confirmation.
- -s : 'Soft' reset: Only clears your namespace, leaving history intact.
- References to objects may be kept. By default (without this option),
- we do a 'hard' reset, giving you a new session and removing all
- references to objects from the current session.
- Examples
- --------
- In [6]: a = 1
- In [7]: a
- Out[7]: 1
- In [8]: 'a' in _ip.user_ns
- Out[8]: True
- In [9]: %reset -f
- In [1]: 'a' in _ip.user_ns
- Out[1]: False
魔术命令默认是可以不带百分号使用的,只要没有定义与其同名的变量即可。这个技术叫做automagic,可以通过%automagic打开或关闭。
由于可以在IPython系统中直接访问它的文档,因此我建议你浏览一下所有这些特殊的命令(输入%quickref或%magic即可)。我将着重讲解几个重要的有助于交互式计算和Python开发的魔术命令。
基于Qt的富GUI控制台
IPython团队开发了一个基于Qt框架(其目的是为终端应用程序提供诸如内嵌图片、多行编辑、语法高亮之类的富文本编辑功能)的GUI控制台(见图3-2)。如果你已经安装了PyQt或PySide,使用下面这条命令来启动的话即可为其添加绘图功能:
- ipython qtconsole --pylab=inline
Qt控制台可以通过标签页的形式启动多个IPython进程,这就使你能够在多个任务之间轻松切换。它也可以跟IPython HTML Notebook应用程序共享同一个进程,稍后我将专门对此进行讲解。
matplotlib集成与pylab模式
导致IPython广泛应用于科学计算领域的部分原因是它能跟matplotlib这样的库以及其他GUI工具集默契配合。即使你从未使用过matplotlib也不用担心,本书稍后会对其进行详细讲解。如果在标准Python shell中创建一个matplotlib绘图窗口,你就会郁闷地发现,GUI的事件循环会接管Python会话的控制权,直到该绘图窗口关闭为止。这自然无法实现交互式的数据分析和可视化,因此IPython对各个GUI框架进行了专门的处理以使其能够跟shell配合得天衣无缝。
通常,我们通过在启动IPython时加上—pylab(注意是两个短划线)标记来集成matplotlib(见图3-3)。
- $ ipython --pylab
图3-2:IPython的Qt控制台
这样会导致几个结果。第一,IPython会启用默认GUI后台集成,这样matplotlib绘图窗口的创建就没问题了。第二,NumPy和matplotlib的大部分功能会被引入到最顶层的interactive命名空间以产生一个交互式的计算环境(就像MATLAB和其他领域特定型科学计算环境那样)。也可以通过%gui对此进行手工设置(详情请执行%gui?)。
译注5:也有译作内视、自省的,不过更多译作内省。
译注6:注意文件的路径,这里实际上用的是默认路径。简单一点的办法就是直接写绝对路径,肯定不出错。
译注7:该命名空间的名字就是interactive。
译注8:Windows中此法行不通,需要用右键菜单中的粘贴功能,否则仅显示第一行。
译注9:注意,这里说的是“一切”。
译注10:注意,由于是立即整体执行,所以不要复制%paste。没事干的话倒是可以试试。
译注11:建议始终用这个,虽然稍微麻烦一点,但是出错的可能性小很多。