魔法(Magic)命令
IPython提供了许多魔法命令,使得在IPython环境中的操作更加得心应手。魔法命令都以%或者%%开头,以%开头的成为行命令,%%开头的称为单元命令。行命令只对命令所在的行有效,而单元命令则必须出现在单元的第一行,对整个单元的代码进行处理。
执行%magic可以查看关于各个命令的说明,而在命令之后添加?可以查看该命令的详细说明。
显示matplotlib图表
matplotlib是最著名的Python图表绘制扩展库,它支持输出多种格式的图形图像,并且可以使用多种GUI界面库交互式地显示图表。使用%matplotlib命令可以将matplotlib的图表直接嵌入到Notebook之中,或者使用指定的界面库显示图表,它有一个参数指定matplotlib图表的显示方式。
在下面的例子中,inline表示将图表嵌入到Notebook中。因此最后一行pl.plot()所创建的图表将直接显示在该单元之下,由于我们不需要查看最后一行返回的对象,因此以分号结束该行。
%matplotlib inline import pylab as pl pl.seed(1) data = pl.randn(100) pl.plot(data);
内嵌图表的输出格式缺省为PNG,可以通过%config命令修改这个配置。%config命令可以配置IPython中的各个可配置对象,其中InlineBackend对象为matplotlib输出内嵌图表时所使用的对象,我们配置它的figure_format="svg",这样将内嵌图表的输出格式修改为SVG。
%config InlineBackend.figure_format="svg" %matplotlib inline pl.plot(data);
内嵌图表很适合制作图文并茂的Notebook,然而它们是静态的无法进行交互。这时可以将图表输出模式修改为使用GUI界面库,下面的qt4表示使用QT4界面库显示图表。请读者根据自己系统的配置,选择合适的界面库:’gtk’, ‘osx’, ‘qt’, qt4’, ‘tk’, ‘wx’。
执行下面的语句将弹出一个窗口显示图表,可以通过鼠标和键盘与此图表交互。请注意该功能只能在运行IPython Kernel的机器上显示图表。
%matplotlib qt4 pl.plot(data);
性能分析
性能分析对编写处理大量数据的程序非常重要,特别是Python这样的动态语言,一条语句可能会执行很多内容,有的是动态的,有的调用二进制扩展库,不进行性能分析,就无法对程序进行优化。IPython提供了许多进行性能分析的魔法命令。
%timeit调用timeit模块对单行语句重复执行多次,计算出其执行时间。下面的代码测试修改列表单个元素所需的时间。
a = [1,2,3] %timeit a[1] = 10
10000000 loops, best of 3: 164 ns per loop
%%timeit则用于测试整个单元中代码的执行时间。下面的代码测试空列表中循环添加10个元素所许的时间:
%%timeit a = [] for i in xrange(10): a.append(i)
100000 loops, best of 3: 3.85 µs per loop
timeit命令会重复执行代码多次,而time则只执行一次代码,输出代码的执行情况,和timeit命令一样,它可以作为行命令和单元命令。下面的代码统计往空列表中添加10万个元素所需的时间。
%%time a = [] for i in xrange(100000): a.append(i)
CPU times: user 44 ms, sys: 4 ms, total: 48 ms Wall time: 51.9 ms
time和timeit命令都将信息使用print输出,如果希望用程序分析这些信息,可以使用%%capture命令,将单元格的输出保存为一个对象。下面的程序对不同长度的数组调用sort()函数进行排序,并使用%timeit命令统计排序所需的时间。为了加快程序的计算速度,这里通过-n20指定代码的运行次数为20次。由于使用了%%capture命令,程序执行之后没有输出,所有输出都被保存进了result对象。
%%capture result import numpy as np for n in [1000, 5000, 10000, 50000, 100000, 500000]: arr = np.random.rand(n) print "n={0}".format(n) %timeit -n20 np.sort(arr)
result.stdout属性中保存通过标准输出管道中的输出信息:
print result.stdout
n=1000 20 loops, best of 3: 127 us per loop n=5000 20 loops, best of 3: 746 us per loop n=10000 20 loops, best of 3: 1.69 ms per loop n=50000 20 loops, best of 3: 9.22 ms per loop n=100000 20 loops, best of 3: 19.7 ms per loop n=500000 20 loops, best of 3: 110 ms per loop
下面的代码使用re模块从上面的字符串中获取数组长度和排序执行时间的信息,并将其绘制成图表。图表的横坐标为对数坐标轴,表示数组的长度;纵坐标为平均每个元素所需的排序时间。可以看出每个元素所需的平均排序时间与数组的长度的对数成正比,因此可以计算出排序函数sort()的时间复杂度为:。
def tosec(t): units = {"ns":1e-9, "us":1e-6, "ms":1e-3, "s":1} value, unit = t.strip().split() return float(value) * units[unit] import re info = re.findall(r"n=(.+?)\n.+?best of 3: (.+?) per loop", result.stdout) info = [(int(t0), tosec(t1)) for t0, t1 in info] x, y = np.r_[info].T pl.semilogx(x, y/x, "-o");
%%prun命令调用profile模块,对单元中的代码进行性能剖析。下面的性能剖析显示fib()运行了21891次,而fib_fast()则只运行了20次。
%%nopage %%prun def fib(n): if n < 2: return 1 else: return fib(n-1) + fib(n-2) def fib_fast(n, a=1, b=1): if n == 1: return b else: return fib_fast(n-1, b, a+b) fib(20) fib_fast(20)
21913 function calls (4 primitive calls) in 0.084 seconds Ordered by: internal time ncalls tottime percall cumtime percall filename:lineno(function) 21891/1 0.084 0.000 0.084 0.084 <string>:2(fib) 20/1 0.000 0.000 0.000 0.000 <string>:8(fib_fast) 1 0.000 0.000 0.084 0.084 <string>:2(<module>) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
代码调试
%debug命令用于调试代码,它有两种用法。一种是在执行代码之前设置断点进行调试,第二种则是在代码抛出异常之后,执行%debug命令查看调用堆栈。下面先演示第二种方法的用法:
import pylab as pl import numpy as np def test_debug(): x = np.linspace(1, 50, 10000) img = np.sin(x*np.cos(x)) pl.imshow(img) pl.show() test_debug()
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-8-718b55b6e471> in <module>() 8 pl.show() 9 ---> 10 test_debug() <ipython-input-8-718b55b6e471> in test_debug() 5 x = np.linspace(1, 50, 10000) 6 img = np.sin(x*np.cos(x)) ----> 7 pl.imshow(img) 8 pl.show() 9 /home/hyry/anaconda/lib/python2.7/site-packages/matplotlib/pyplot.pyc in imshow(X, cmap, norm, aspect, interpolation, alpha, vmin, vmax, origin, extent, shape, filternorm, filterrad, imlim, resample, url, hold, **kwargs) 2735 vmax=vmax, origin=origin, extent=extent, shape=shape, 2736 filternorm=filternorm, filterrad=filterrad, -> 2737 imlim=imlim, resample=resample, url=url, **kwargs) 2738 draw_if_interactive() 2739 finally: /home/hyry/anaconda/lib/python2.7/site-packages/matplotlib/axes.pyc in imshow(self, X, cmap, norm, aspect, interpolation, alpha, vmin, vmax, origin, extent, shape, filternorm, filterrad, imlim, resample, url, **kwargs) 7103 filterrad=filterrad, resample=resample, **kwargs) 7104 -> 7105 im.set_data(X) 7106 im.set_alpha(alpha) 7107 self._set_artist_props(im) /home/hyry/anaconda/lib/python2.7/site-packages/matplotlib/image.pyc in set_data(self, A) 420 if (self._A.ndim not in (2, 3) or 421 (self._A.ndim == 3 and self._A.shape[-1] not in (3, 4))): --> 422 raise TypeError("Invalid dimensions for image data") 423 424 self._imcache =None TypeError: Invalid dimensions for image data
%debug
> [1;32m/home/hyry/anaconda/lib/python2.7/site-packages/matplotlib/image.py [0m(422) [0;36mset_data [1;34m() [0m [1;32m 421 [1;33m (self._A.ndim == 3 and self._A.shape[-1] not in (3, 4))): [0m [1;32m--> 422 [1;33m [1;32mraise [0m [0mTypeError [0m [1;33m( [0m [1;34m"Invalid dimensions for image data" [0m [1;33m) [0m [1;33m [0m [0m [0m [1;32m 423 [1;33m [1;33m [0m [0m [0m ipdb> l
%config InlineBackend.figure_format="svg" %matplotlib inline def test_debug(): x = np.linspace(1, 50, 10000) img = np.sin(x*np.cos(x)).reshape(100, -1) pl.imshow(img) pl.show() test_debug()
%%writefile debug_test.py a = 1 b = 2 print a + b
Writing debug_test.py
%debug --breakpoint debug_test.py:2
Breakpoint 1 at /home/hyry/Dropbox/scipybook2/debug_test.py:2 NOTE: Enter 'c' at the ipdb> prompt to continue execution.
%run -d debug_test.py
Breakpoint 1 at /home/hyry/Dropbox/scipybook2/debug_test.py:1 NOTE: Enter 'c' at the ipdb> prompt to continue execution. > [1;32m/home/hyry/Dropbox/scipybook2/debug_test.py [0m(1) [0;36m<module> [1;34m() [0m [1;31m1 [1;32m---> 1 [1;33m [0ma [0m [1;33m= [0m [1;36m1 [0m [1;33m [0m [0m [0m [1;32m 2 [1;33m [0mb [0m [1;33m= [0m [1;36m2 [0m [1;33m [0m [0m [0m [1;32m 3 [1;33m [1;32mprint [0m [0ma [0m [1;33m+ [0m [0mb [0m [1;33m [0m [0m [0m ipdb> c
%run?