1.2.2 魔法(Magic)命令(2)
图1 9显示了排序的耗时结果。横坐标为对数坐标轴,表示数组的长度;纵坐标为平均每个元素所需的排序时间。可以看出每个元素所需的平均排序时间与数组长度的对数成正比,因此可以计算出排序函数sorted()的时间复杂度为:O(nlogn)。
%%prun命令调用profile模块,对单元中的代码进行性能剖析。下面的性能剖析显示fib()运行了21891次,而fib_fast()则只运行了20次:
%%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):
ifn== 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.007 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
21891/1 0.007 0.000 0.007 0.007:2(fib)
20/1 0.000 0.000 0.000 0.000:8(fib_fast)
1 0.000 0.000 0.007 0.007:2()
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler'
objects}
3. 代码调试
%debug命令用于调试代码,它有两种用法:一种是在执行代码之前设置断点进行调试;另一种则是在代码抛出异常之后,执行%debug命令查看调用堆栈。下面先演示第二种用法:
import math
def sinc(x):
return math.sin(x) / x
[sinc(x) for x in range(5)]
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
in()
4 return math.sin(x) / x
5
---->6 [sinc(x) for x in range(5)]
in sinc(x)
2
3 def sinc(x):
---->4 return math.sin(x) / x
5
6 [sinc(x) for x in range(5)]
ZeroDivisionError: float division by zero
上面的程序抛出了ZeroDivisionError异常,下面用%debug查看调用堆栈。在调试模式下可以使用pdb模块提供的调试命令,例如用命令p x显示变量x的值:
%debug
>(4)sinc()
3 def sinc(x):
---->4 return math.sin(x) / x
5
ipdb>p x
0
ipdb>q
还可以先设置断点,然后运行程序。但是%debug的断点需要指定文件名和行号,使用起来并不是太方便。本书提供了%%func_debug单元命令,可以通过它指定中断运行的函数。在下面的例子中,程序将在numpy.unique()的***行中断运行,然后通过输入命令n单步运行程序,***输入命令c继续运行:
%%func_debug np.unique
np.unique([1, 2, 5, 4, 2])
Breakpoint 1 at c:\winpython-32bit-2.7.9.2\python-2.7.9\lib\site-packages\numpy\lib\arraysetops.py:96
NOTE: Enter 'c' at the ipdb>prompt to continue execution.
>c:\winpython-32bit-2.7.9.2\python-2.7.9\lib\site-packages\numpy\lib\arraysetops.py(173)
unique()
172 """
-->173ar=np.asanyarray(ar).flatten()
174
ipdb>n
>c:\winpython-32bit-2.7.9.2\python-2.7.9\lib\site-packages\numpy\lib\arraysetops.py(175)
unique()
174
-->175optional_indices=return_indexor return_inverse
176optional_returns=optional_indicesor return_counts
ipdb>c
4. 自定义的魔法命令
scpy2.utils.nbmagics:该模块中定义了本书提供的魔法命令,如果读者使用本书提供的批处理运行Notebook,则该模块已经载入。notebooks\01-intro\scpy2-magics.ipynb是这些魔法命令的使用说明。
IPython提供了很方便的自定义魔法命令的方法。最简单的方法就是使用register_line_magic和register_cell_magic装饰器将函数转换为魔法命令。下面的例子使用register_line_magic定义了一个行魔法命令%find,它在指定的对象中搜索与目标匹配的属性名:
from IPython.core.magic import register_line_magic
@register_line_magic
def find(line):
from IPython.core.getipython import get_ipython
from fnmatch import fnmatch
items=line.split()
patterns,target=items[:-1], items[-1]
ipython=get_ipython()
names=dir(ipython.ev(target))
results= []
for pattern in patterns:
for name in names:
if fnmatch(name, pattern):
results.append(name)
return results
当调用%find行魔法命令时,魔法命令后面的所有内容都传递给line参数。 按照空格对line进行分隔,除***一个元素之外,其余的元素都作为搜索模板,而***一个参数则为搜索的目标。 通过get_ipython()函数获得表示IPython运算核的对象,通过该对象可以操作运算核。 调用运算核的ev()方法对表达式target求值以得到实际的对象,并用dir()获取该对象的所有属性名。
***使用fnmatch模块对搜索模板和属性名进行匹配,将匹配结果保存到results并返回。下面使用%find命令在numpy模块中搜索所有以array开头或包含mul的属性名:
import numpy as np
names= %find array* *mul* np
names
['array', 'array2string', 'array_equal', 'array_equiv',
'array_repr', 'array_split', 'array_str', 'multiply',
'polymul', 'ravel_multi_index']
喜欢的朋友可以添加我们的微信账号:
51CTO读书频道二维码
51CTO读书频道活动讨论群:342347198
【责任编辑:book TEL:(010)68476606】
点赞 0