14.4. IPython魔术命令

前两小节展示了怎样使用IPython,令你在其中执行Python代码更加有效和具有交互性。现在我们要开始讨论一些IPython增强的语言特性。这些特性被称为IPython的魔术命令,它们都是以%字符开头的。这些魔术命令被设计用来简洁地实现很多通用的标准数据科学问题。魔术命令分成两种模式:行魔术,以一个%开头,是对于一行的输入进行魔术处理的;另一种是单元格魔术,以两个%%开头,是对于多行的输入进行魔术处理的。本节我们会展示和讨论一些例子,然后本章后续小节会对部分有用的魔术命令进行详细的讨论。

14.4.1. 粘贴代码块:%paste%cpaste

当使用IPython解释器时,我们会遇到一个坑,就是粘贴多行代码块是会出现很多意料之外的错误,尤其是当存在缩进和提示符的情况下。其中一个常见的情况就是当你在网上找到一些示例代码,然后想将它们粘贴到你的解释器中。例如下面这个简单的函数:

>>> def donothing(x):
...     return x

这段代码在Python解释器中就会像上面那样展示,但是如果你采用通常的复制粘贴大法将它们粘贴到IPython的时候,错误就发生了:

In [2]: >>> def donothing(x):
   ...:     ...     return x
   ...:
  File "<ipython-input-20-5a66c8964687>", line 2
    ...     return x
                 ^
SyntaxError: invalid syntax

在直接粘贴的情况下,解释器被额外的提示符号搞蒙了。不怕,IPyton的%paste魔术命令是专门为了处理这种情况(多行代码块,带提示符号)设计的:

In [3]: %paste
>>> def donothing(x):
...     return x

## -- End pasted text --

%paste命令既输入了多行代码又执行了它们,因此donothing函数已经可以使用了:

In [4]: donothing(10)
Out[4]: 10

还有一个魔术命令%cpaste也是类似的作用,它会打开一个交互的多行提示符,允许你粘贴多个代码块然后批量执行它们:

In [5]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:>>> def donothing(x):
:...     return x
:--

这些魔术命令,还有我们马上会看到的其他命令,提供了标准Python解释器很难或无法提供的功能。

14.4.2. 执行外部代码:%run

当你使用Python开发更多代码之后,你会发现你可能需要两个环境,在IPython中交互式的进行探索和快速验证,使用文本编辑器保存那些以后你需要重用的代码。当你需要在IPython中运行你已经保存好的Python代码文件时,你不需要打开一个新的进程执行它们,也不需要将它们的代码粘贴进来,你可以使用%run魔术。

例如,你创建了一个myscript.py文件,里面的内容是:

#-------------------------------------
# file: myscript.py

def square(x):
    """square a number"""
    return x ** 2

for N in range(1, 4):
    print(N, "squared is", square(N))

你可以在你的IPython shell中这样执行这个Python代码文件:

In [6]: %run myscript.py
1 squared is 1
2 squared is 4
3 squared is 9

你应该注意到了,当你执行完这个脚本文件之后,任何定义了的函数也可以在你当前的IPython会话中使用了。

In [7]: square(5)
Out[7]: 25

还有一些参数可以精细控制你的代码文件如何执行;你可以像之前介绍的那样查看它的文档,只需要在IPython shell中输入%run?即可。

14.4.3. 代码执行计时:%timeit

下面介绍的魔术命令是%timeit,它会自动测试统计紧跟之后的单行Python语句的执行性能(时间)。例如我们需要测试列表解析的性能:

In [8]: %timeit L = [n ** 2 for n in range(1000)]
1000 loops, best of 3: 325 µs per loop

使用%timeit的时候,它会自动执行多次,以获取更有效的结果。对于多行的代码来说,增加一个%号,会将本魔术命令变成单元格模式,因此它能测试多行输入的性能。例如,下面是一段相同功能的列表初始化,使用的for循环:

In [9]: %%timeit
   ...: L = []
   ...: for n in range(1000):
   ...:     L.append(n ** 2)
   ...:
1000 loops, best of 3: 373 µs per loop

从上面的结果可以看出来,使用列表解析能比使用for循环的方式提升10%的运行速度。我们将在性能测算和计时中更加详细的讨论它。

14.4.4. 魔术命令帮助:?%magic%lsmagic

就像普通的Python对象,IPython魔术命令也有docstring,这些文档可以按照我们之前的方式简单的获取到。举个例子,想要查阅%timeit的文档,仅需输入:

In [10]: %timeit?

其他魔术命令和文档也可以类似获得。要获得魔术命令的通用描述以及它们的例子,你可以输入:

In [11]: %magic

如果想要快速简单地列出所有可用的魔术命令,输入:

In [12]: %lsmagic

最后,你可以了解自定义魔术命令的有关知识。但是本书不会讨论这个方面,如果读者感兴趣,请参见更多IPython资源