In [19]:
a = 5
In [20]:
a
Out[20]:
In [21]:
import numpy as np
from numpy.random import randn
data = {i: randn() for i in range(7)}
print(data)
data1 = {j: j**2 for j in range(5)}
print(data1)
In [22]:
an_apple = 27
In [23]:
an_example = 42
In [24]:
an_ #按下tab键就会看到之前定义的变量会被显示出来,方便我们做出选择。
此外,我们还可以在任何对象之后输入一个句点来方便地补全方法和属性的输入:
In [1]:
import IPython
print(IPython.sys_info())
In [3]:
a = [1,2,3]
In [4]:
a.append(0)
a
Out[4]:
In [5]:
import datetime
In [6]:
dt = datetime.time(22,2,2)
In [7]:
dd = datetime.date(2017,2,2)
In [8]:
print("%s %s" % (dt,dd))
Tab键自动完成成功不只可以搜索命名空间和自动完成对象或模块属性。当我们输入任何看上去像文件路径的东西时(即便是在一个Python字符串中),按下Tab键即可找出电脑文件系统中与之匹配的东西。
In [ ]:
./ #按下Tab键, 如果你当前目录下有文件或者目录,会给出提示。
In [9]:
b=[1,2,3]
In [10]:
b?
上面执行完,jupyter会跳出一个小窗口并且显示如下:
Type: list
String form: [1, 2, 3]
Length: 3
Docstring:
list() -> new empty list
list(iterable) -> new list initialized from iterable's items
如果对象是一个函数或者实例方法,则它的docstring(如果有的话)也会显示出来。例如:
In [11]:
def add_numbers(a,b):
#引号部分则为docstring
"""
Add two numbers together
Returns
-------
the_sum: type of arguments
"""
return a+b
add_numbers(1,2)
Out[11]:
In [12]:
add_numbers?
#加一个问号执行会显示上述我已经编写好的docstring,这样在忘记函数作用的时候还是很不错的功能。
In [13]:
add_numbers??
#加两个问号则会显示该函数的源代码
?还有一个用法,即搜索IPython的命名空间,类似于标准UNIX或者Windows命令行中的那种用法。一些字符再配以通配符即可显示出所有与该通配符表达式相匹配的名称。例如我们可以列出NumPy顶级命名空间中含有“load"的所有函数。
In [14]:
import numpy as np
np.*load*?
In [46]:
def f(x,y,z):
return (x+y)/z
a=5
b=6
c=8
result = f(a,b,c)
print(result)
In [48]:
#执行
%run ./chapter03/simple01.py
上述脚本simple01.py是在一个空的命名空间中运行的,没有任何import,也没有定义任何其他的变量,所以其行为跟在命令行运行是一样的。此后,该脚本中所定义的变量(包括脚本中的import、函数、全局变量)就可以在当前jupyter notebook中进行访问(除非有其他错误或则异常)
In [49]:
result
Out[49]:
如果Python脚本中需要用到命令行参数(通过 sys.argv访问),可以将参数放到文件路径的后面,就像在命令行执行那样。
如果希望脚本执行的时候会访问当前jupyter notebook中的变量,应该用…%run -i script.py,例如
我在chapter03文件夹中写下
x = 32
add = x + result
print('add is %d' % (add))
In [52]:
%run -i ./chapter03/simple02.py #-i即interactive
在IPython shell(注意,我这里强调一下,并不是在jupyter notebook中,而是ipython shell,虽然我有时候 把他们两个说的好像等效一样,但是两者还是不同的)中执行代码的最简单方式就是粘贴剪贴板中的代码。虽然这种做法很粗糙, 但是在实际工作中就很有用。比如,在开发一个复杂或耗时的程序时候,我们可能需要一段 一段地执行脚本,以便查看各个阶段所加载的数据以及产生的结果。又比如说,在网上找到了 一个何用的代码,但是又不想专门为其新建一个.py文件。
多数情况下,我们可以通过“Ctrl-Shift-V”将粘贴版中的代码片段粘贴出来(windows中)。
%paste 和 %cpaste 这两个魔术函数可以粘贴剪贴板中的一切文本。在ipython shell中这两个函数 可以帮助粘贴。后者%cpaste相比于%paste只是多了粘贴代码的特殊提示符,可以一行一行粘贴。
In [ ]:
#下面我把我在ipython中执行的代码
$ ipython
Python 3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:x = 1
:if x == 1:
: print("x is 1.")
:
:--
x is 1.
对于我自己而言,我喜欢用git bash,然后在里面折腾vim. 当然我有时候也用IDE
In [1]:
%run ./pydata-book/ch03/ipython_bug.py
拥有额外的上下文代码参考是它相对于标准python解释器的一大优势。上下文代码参考的数量可以通过%mode魔术命令进行控制,既可以少(与标准python解释器相同)也可以多(带有函数参数值以及其他信息)。本章后面还会讲到如果在出现异常之后进入跟踪栈进行交互式的事后调试post-mortem debugging.
In [17]:
import numpy as np
from numpy.random import randn
a = randn(3,3,3)
a
Out[17]:
In [18]:
%timeit np.dot(a,a)
魔术命令可以看作运行于IPython系统中的命令行程序。它们大都还有一些“命令行”,使用“?”即可查看其选项
In [20]:
%reset?
上面执行后,会跳出它的docstring
In [21]:
a = 1
In [22]:
a
Out[22]:
In [23]:
'a' in _ip.user_ns # 不知道为什么这里没有执行通过?
In [10]:
%reset -f
In [9]:
'a' in __ip.user__ns
常用的python魔术命令
命令 | 功能 |
---|---|
%quickref | 显示IPython的快速参考 |
%magic | 显示所有魔术命令的详细文档 |
%debug | 从最新的异常跟踪的底部进入交互式调试器 |
%hist | #打印命令的输入(可选输出)历史 |
%pdb | 在异常发生后自动进入调试器 |
%paste | 执行粘贴版中的python代码 |
%reset | 删除interactive命名空间中的全部变量、名称 |
%page OBJECT | 通过分页器打印输出 OBJECT |
%run script.py | 在IPython中执行脚本 |
%run statement | 通过cProfile执行statement,并打印分析器的输出结果 |
%time statement | 报告statement的执行时间 |
%timeit statement | 多次执行statement以计算系统平均执行时间。对那些执行时间非常小的代码很有用 |
%who、%who_ls、%whos | 显示interactive命名空间中定义的变量,信息级别、冗余度可变 |
%xdel variable | 删除variable,并尝试清楚其在IPython中的对象上的一切引用 |
导致Ipython广泛应用于科学计算领域的部分原因是它跟matplotlib这样的库以及GUI工具集默契配合。
通常我们通过在启动Ipython时候添加--pylab标记来集成matplotlib
In [ ]:
#在terminal 输入
ipython --pylab
#回显中会出现部分关于matplotlib的字段
#IPython 6.2.0 -- An enhanced Interactive Python. Type '?' for help.
#Using matplotlib backend: Qt5Agg
上述的操作会导致几个结果:
IPython 会启动默认GUI后台集成,这样matplotib绘图窗口创建就不会出现问题;
Numpy和matplotlib的大部分功能会被引入到最顶层的interactive命名空间以产生一个交互式的计算环境(类似matlab等)。也可以通过%gui对此进行手工设置(详情请执行%gui?)
In [5]:
#原书给了一个在ipython命令行的例子
#但是,我这里用jupyter notebook来进行演示
# 我这里的代码跟原书可能不是很相同,
#我参考的是matplotlib image tutorial
%matplotlib inline
import matplotlib.image as mpimg
import numpy as np
import matplotlib.pyplot as plt
img=mpimg.imread('pydata-book/ch03/stinkbug.png')
In [6]:
plt.imshow(img)
Out[6]:
In [21]:
#Here, we use Pillow library to resize the figure
from PIL import Image
import matplotlib.pyplot as plt
img = Image.open('pydata-book/ch03/stinkbug.png')
img1 = img
img.thumbnail((64,64), Image.ANTIALIAS) ## resizes image in-place
img1.thumbnail((256,256), Image.ANTIALIAS)
imgplot = plt.imshow(img)
img1plot = plt.imshow(img1)
In [4]:
%matplotlib inline
import matplotlib.pylab as plab
from numpy.random import randn
plab.plot(randn(1000).cumsum())
Out[4]:
In [5]:
#在ipython terminal执行
%run chapter03/simple01.py
如果我们想在修改了simple01.py(当然也可以不改)后再次执行上面的操作,只需要输入 %run 命令的前几个字符并按下“ctrl+P”键或者向上箭头就会在命令历史的第一个发现它. (可能是因为我用的是git bash on windows,我自己并未测试成功书中的这个操作;但是在Linux中,我测试是有效的)。此外,ctrl-R可以实现部分增量搜索,跟Unix shell中的readline所提供的功能一样,并且ctrl-R将会循环搜索命令历史中每一条与输入相符的行。
例如,第一次ctrl-R后,我输入了c,ipython返回给我的是:
In [6]: c=a+b
I-search backward: c
再按依次ctrl-R,则变成了历史中含c这个关键字的另一个命令
In [6]: c = c + 1
I-search backward: c
IPython shell和jupyter notebook中,最近的两个输出分别保存在 _ 和 __ 两个变量中
In [1]:
a=3
In [2]:
a
Out[2]:
In [3]:
b=4
In [4]:
b
Out[4]:
In [5]:
__
Out[5]:
In [6]:
c=5
c
Out[6]:
In [7]:
_
Out[7]:
输入的文本被保存在名为 _iX 的变量中,其中X是输入行的行号。每个输入变量都有一个对应的输出变量 _X。例如:
In [8]:
foo = 'bar'
In [9]:
foo
Out[9]:
In [10]:
_i9
Out[10]:
In [11]:
_9
Out[11]:
由于输入变量是字符串,因此可用python的exec关键字重新执行: exec _i9
有几个魔术命令可用于输入、输出历史。%hist用于打印全部或部分历史,可以选择是否带行号
In [13]:
%hist
%reset 用于清空 interactive 命名空间,并可选择是否清空输入和输出缓存。%xdel 用于从IPython系统中移除特定对象的一切引用。
In [14]:
%reset
In [16]:
a #由于上面已经清理了命名空间,所以python并不知道a是多少。
注意:在处理大数据集时,需注意IPython的输入和输出历史,它会导致所有对象引用都无法被垃圾收集器处理(即释放内存),即使用del关键字将变量从interactive命名空间中删除也不行。对于这种情况,谨慎地使用%xdel和%reset将有助于避免出现内存方面的问题。
In [17]:
%logstart
IPython的日志功能开在任何时刻开气,以便记录整个会话。%logstart的具体选项可以参考帮助文档。此外还可以看看几个与之配套的命令:%logoff, %logon, %logstate, 以及 %logstop
In [18]:
%logstart?
IPython 的另一重要特点就是它跟操作系统的shell结合地非常紧密。即我们可以直接在IPython中实现标准的Windows或unix命令行活动。例如,执行shell命令、更改目录、将命令的执行结果保存在Python对象中等。此外,它还提供了shell命令别名以及目录书签等功能。
下表总结了用于调用shell命令的魔术命令及其语法。本笔记后面还会介绍这些功能。
命令 | 说明 |
---|---|
!cmd | 在系统shell中执行cmd |
output = !cmd args | 执行cmd,将stdout存放在output中 |
%alias alias_name cmd | 为系统shell命令定义别名 |
%bookmark | 使用IPtyhon的目录书签功能 |
%cd directory | 将系统工作目录更改为directory |
%pwd | 返回当前工作目录 |
%pushed directory | 将当前目录入栈,并转向目标目录 (这个不懂??) |
%popd | 弹出栈顶目录,并转向该目录 |
%dirs | 返回一个含有当前目录栈的列表 |
%dhist | 打印目录访问历史 |
%env | 以dict形式返回系统环境变量 |
yang@comet-1.edu ~ 19:17:51 >ipython Python 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58) Type 'copyright', 'credits' or 'license' for more information IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]:
In [1]: !python Python 3.6.1 |Continuum Analytics, Inc.| (default, May 11 2017, 13:09:58) [GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux Type "help", "copyright", "credits" or "license" for more information.
此外,还可将shell命令的控制台输出存放到变量中,只需要将 !开头的表达式赋值给变量即可。例如在Linux中
In [ ]:
In [4]: my_current_dir = !pwd
In [5]: my_current_dir
Out[5]: ['/home/ywfang']
In [ ]:
返回的python对象my_current_dir实际上是一个含有控制台输出结果的自定义列表类型。
在使用!时,IPython 还允许使用当前环境中定义的python值。只需在变量名前面加上美元符号($)即可:
In [ ]:
#在ipython shell中
In [1]: foo = 'note*'
In [2]: !ls $foo
notebook.log
魔术命令 %alias 可以为shell命令自定义简称。例:
In [3]: %alias ll ls -l
In [4]: ll total 426 drwxr-xr-x 1 YWFANG 197609 0 9月 21 22:47 appendix-A -rw-r--r-- 1 YWFANG 197609 47204 10月 8 10:48 appendix-A-note.ipynb
可以一次执行多条命令,只需要将她们写在一行并以分号隔开(在Windows中,这个可能不可行,但是Linux可以通过)
In [3]: %alias test_fang (ls -l; cd ml; ls -l; cd ..)
In [4]: test_fang total 211 drwxr-xr-x 2 ywfang yun112 2 Aug 22 18:45 Desktop -rw-r--r-- 1 ywfang yun112 11148 Jul 2 22:02 bashrc-fang-20170703 drwxr-xr-x 9 ywfang yun112 9 Jul 7 01:45 glibc-2.14 drwxr-xr-x 3 ywfang yun112 3 Jul 2 23:10 intel -rwxr-xr-x 1 ywfang yun112 645 Sep 19 04:51 jupter_notebook drwxr-xr-x 3 ywfang yun112 5 Jul 7 18:51 materials drwxr-xr-x 20 ywfang yun112 21 Aug 22 18:02 miniconda3 drwxr-xr-x 3 ywfang yun112 3 Sep 4 18:39 ml -rw-r--r-- 1 ywfang yun112 826 Sep 30 08:35 notebook.log drwxr-xr-x 3 ywfang yun112 4 Aug 22 18:21 pwwork drwxr-xr-x 6 ywfang yun112 14 Aug 22 19:04 software drwxr-xr-x 5 ywfang yun112 6 Sep 4 18:56 tensorflow drwxr-xr-x 5 ywfang yun112 6 Sep 4 18:53 tf1.2-py3.6 drwxr-xr-x 5 ywfang yun112 6 Sep 4 18:54 tf12-py36 drwxr-xr-x 6 ywfang yun112 518 Jun 20 01:33 tool total 1 drwxr-xr-x 3 ywfang yun112 3 Sep 4 18:39 tensorflow
注意,IPython会在会话结束时立即"忘记"我们前面所定义的一切别名。如果要进行永久性的别名设置,需要使用配置系统。之后会进行介绍。
In [11]:
%bookmark db D:\PhDinECNU #windows中的写法;如果是Linux,应该为/d/PhDinECNU/
%bookmark dt D:\temp
In [9]:
%cd db
定义好之后就可以在ipython shell(或jupyter notebook)中使用魔术命令%cd db来使用这些标签
如果书签的名字与当前工作目录中某个名字冲突时,可通过 -b 标记(起作用是覆写)使用书签目录。%bookmark的 -l 选项的作用是列出所有书签。
In [12]:
%bookmark -l
In [13]:
%reset
In [14]:
%cd D:\PhDinECNU\readingnotes\readingnotes\machine-learning\McKinney-pythonbook2013
In [15]:
%run pydata-book/ch03/ipython_bug.py
In [ ]:
%debug
在这个 pdb 调试器中,我们可以执行任意Python 代码并查看各个栈帧中的一切对象和数据,这就相当于解释器还留了条后路给我们。默认是从最低级开始的,即错误发生的地方,在上面ipdb>后面输入u (up) 或者 d (down) 即可在栈跟踪的各级别之间进行切换。
In [ ]:
执行%pdb命令可以让IPython在出现异常之后直接调用调试器,很多人都认为这一功能很实用。
此外调试器还能为代码开发提供帮助,尤其当我们想设置断点或者对函数/脚本进行单步调试时。实现这个目的的方式如下所述。
用带有 -d 选项的 %run 命令,这将会在执行脚本文件中的代码之前先打开调试器。必须立即输入 s(或step)才能进入脚本:
In [ ]:
%run -d ./pydata-book/ch03/ipython_bug.py
在此之后,上述文件执行的方式就全凭我们自己说了算了。比如说,在上面那个异常中,我们可以在调用 works_fine 方法的地方设置一个断点,然后输入 c (或者 continue) 使脚本一直运行下去直到该断点时为止。
In [ ]:
%run -d ./pydata-book/ch03/ipython_bug.py
如果想精通这个调试器,必须经过大量的实践。
虽然大部分 IDE 都会自带调试器,但是 IPython 中调试程序的方法往往会带来更高的生产率。
下面是常用的 IPython 调试器命令
命令 | 功能 |
---|---|
h(elp) | 显示命令列表 |
help command | 显示 command 的文档 |
c(ontinue) | 恢复程序的执行 |
q(uit) | 推出调试器,不再执行任何代码 |
b(reak) number | 在当前文件的第 number 行设置一个断点 |
b path/to/file.py:number | 在制定文件的第 numbe 行设置一个断点 |
s(tep) | 单步进入函数调用 |
n(ext) | 执行当前行,并前进到当前级别的下一行 |
u(p)/d(own) | 在函数调用栈中向上或者向下移动 |
a(rgs) | 显示当前函数的参数 |
debug statement | 在新的(递归)调试其中调用语句 statement |
l(ist) statement | 显示当前行,以及当前栈级别上的上下文参考代码 |
w(here) | 打印当前位置的完整栈跟踪 (包括上下文参考代码) |
第一个函数 set_trace 很简单。我们可以将其放在代码中任何希望停下来查看一番的地方,尤其是那些发生异常的地方:
In [ ]:
%run ./pydata-book/ch03/ipython_bug.py
In [ ]:
%debug
In [ ]:
import time
start = time.time()
for i in range(iterations):
#to do something
elapsed_per = (time.time() - start ) / iterations
In [8]:
由于这是一个非常常用的功能,所以IPython提供了两个魔术工具 %time 和 %timeit 来自动完成该过程。%time 一次执行一条语句,然后报告总的执行时间。假设我们有一大堆字符串,希望对几个“能选出具有特殊前缀的字符串”的函数进行比较。下面是一个拥有60万字字符串的数组,以及两个不同的“能够选出其中以foo开头的字符串”的方法:
In [9]:
# a huge string array
strings = ['foo', 'foobar', 'baz', 'qux', 'python', 'God']*100000
method1 = [x for x in strings if x.startswith('foo')]
method2 = [x for x in strings if x[:3]=='foo']
#These two methos look almost same, but their performances are different.
# See below, I use %time to calculate the excutable time.
In [10]:
%time method1 = [x for x in strings if x.startswith('foo')]
In [11]:
%time method2 = [x for x in strings if x[:3]=='foo']
Wall time是我们感兴趣的数字。所以,看上去第一个方法耗费了接近2倍的时间,但是这并非一个非常精确的结果。如果我们队相同语句多次执行%time的话,就会发现其结果是变化的。为了得到更加精确的结果,我们需要使用魔术函数 %timeit。对于任意语句,它会自动多次执行以产生一个非常精确的平均执行时间
In [12]:
%timeit method = [ x for x in strings if x.startswith('foo')]
In [13]:
%timeit method = [x for x in strings if x[:0]=='foo']
这个很平淡无奇的离子告诉我们这样一个道理:我们有必要了解Python标准库、Numpy、Pandas 以及 本书所用其他库的性能特点。在大型数据分析中,这些不起眼的毫秒数会不断累积产生蝴蝶效应。
对于那些执行时间非常短(甚至是微妙 1e-6 s;或者 纳秒 1e-9 s)的分析语句和函数而言,%timeit 是非常有用的。虽然对于单次执行而言,这些时间小到几乎可以忽略不计。但是我们只要举一个例子,就会发现我们很有必要“分秒必争”:
同样执行100万次一个20微妙的函数,所化时间要比一个5微妙的多出15秒。
在上面我运行的那个例子中,我们可以直接对两个字符串运算进行比较,以了解其性能特点:
In [1]:
x = 'foobar'
y = 'foo'
In [2]:
%timeit x.startswith(y)
In [3]:
%timeit x[:3]==y
代码的性能分析跟代码执行时间密切关联,只是它关注的是耗费时间的位置。Python中,cProfile模块主要用来分析代码性能,它并非转为python设计。cProfile在执行一个程序代码或代码块时,会记录各函数所耗费的时间。
cProfile一般是在命令行上使用的,它将执行整个程序然后输出各个函数的执行时间。
下面,我们就给出了一个简单的例子:在一个循环中执行一些线性代数运算(即计算一个100 * 100 的矩阵的最大本征值绝对值)
In [4]:
import numpy as np
from numpy.linalg import eigvals
def run_experiment(niter = 100):
K = 100
results = []
for _ in range(niter):
mat = np.random.randn(K,K)
max_eigenvalue = np.abs(eigvals(mat)).max()
results.append(max_eigenvalue)
return results
some_results = run_experiment()
print('Largest one we saw: %s' %(np.max(some_results)))
我们将上述脚本内容写入 simple03.py (目录为当前目录下的chapter03目录中),并且执行
In [1]:
!python -m cProfile chapter03/simple03.py
即使这里不明白脚本里面具体做的事情,那也没有关系,反正先这么照着书里先做着,感受下cProfile的作用。
我们可以看到,输出结果是按照函数名排序的(ordered by standard name)。这样就比较难看出哪些地方是最花时间的,因此通常用 -s 标记,换一种排序的规则:
In [2]:
!python -m cProfile -s cumulative chapter03/simple03.py
我们看到此时的排序规则为 Ordered by: cumulative time,这样我们只需要看 cumtime 列即可发现各函数所耗费的总计时间。 注意如果一个函数A调用了函数B,计时器并不会停止而重新计时。cProfile记录的是各函数调用的起始和结束时间,并依次计算总时间。
除了命令行用法外,cProfile 还可以通过编程的方式分析任意代码块的性能。IPython为此提供了一个方便的借口,即 %prun 命令和带 -p 选项的 %run。 %prun的格式跟 cProfile 的差不多,但它分析的是 Python 语句 而不是整个 .py 文件:
In [6]:
%prun -l 7 -s cumulative run_experiment()
在ipython terminal中,执行 %run -p -s cumulative chapter03/simple03.py也能达到上述效果,但是却无法退出IPython。
In [ ]:
# A list of dotted module names of IPython extensions to load.
c.TerminalIPythonApp.extensions = [
'line_profiler',
]
In [7]:
#这个代码可以确认 line_profiler 是否被正常的安装和load
import line_profiler
line_profiler
Out[7]:
line_profiler 可以通过编程方式使用,但是其更强大的一面在于与 Ipython 的交互使用。
假设我们有一个名为 prof_mod 的模块,其代码内容为(我们把prof_mode.py 保存在 chapter03目录下)
In [8]:
from numpy.random import randn
def add_and_sum(x,y):
added = x + y
summed = added.sum(axis=1)
return summed
def call_function():
x = randn(1000,1000)
y = randn(1000,1000)
return add_and_sum(x,y)
如果我们想了解 add_and_sum 函数的性能,%prun 会给出如下所示的结果
In [1]:
%run chapter03/prof_mode.py
In [3]:
x = randn(3000, 3000)
y = randn(3000,3000)
In [4]:
%prun add_and_sum(x,y) #因为我们这里只是测试 add_and_sum 这个函数,所以必须给它实参,所以上面我们给出了 x和y
执行的结果为:
当我们启用 line_profiler 这个扩展后,就会出现新的魔术命令 %lprun。 用法上唯一的区别就是: 必须为 %lprun 指明想要测试哪个或哪些函数。%lprun 的通用语法为:
In [ ]:
%lprun -f func1 -f func2 statement_to_profile
在本例子中,我们想要测试 add_and_sum,于是执行
In [12]:
%lprun -f add_and_sum add_and_sum(x,y)
网上找了下别人也遇到了和我一样的错误,stackoverflow上面有解决方案:
In [6]:
%load_ext line_profiler
然后我们再执行一次
In [7]:
%lprun -f add_and_sum add_and_sum(x,y)
这个结果就容易理解了许多。这里我们测试的只是 add_and_sum 这个函数。上面那个模块中还有一个call_function 函数,我们可以结合 add_and_sum 一起测试,于是最终我们的命令成为了这个样子:
In [8]:
%lprun -f add_and_sum -f call_function call_function()
In [ ]:
综上,当我们需要测试一个程序中的某些函数时,我们需要使用这两行代码:
%load_ext line_profiler
%lprun -f func1 -f func2 statement_to_profile
通常我们会用 %prun (cProfile) 做宏观性能分析,而用 %lprun 来做 微观的性能分析。
注意,在使用 %lprun 时,之所以必须显示指明待测试函数的函数名,是因为“跟踪”每一行代码的时间代价是巨大的。对不感兴趣的函数进行跟踪会对分析结果产生很显著的影响。
IPthon HTML Notebook,即现在的 jupyter notebook。这个其实在我整个笔记中都已经在使用了。notebook项目最初由 Brian Graner 领导的 Ipython 团队从 2011 年开始开发。目前已被广泛使用于开发和数据分析。
首先来看个导入图标的例子,其实这个笔记的开头,我也已经展示过部分这样的功能
In [9]:
import numpy as np
import pandas as pd
print('hello world!')
In [2]:
import numpy as np
import pandas as pd
tips = pd.read_csv('./pydata-book/ch08/tips.csv')
tips.head()
Out[2]:
In [11]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
img = plt.imread('pydata-book/ch03/stinkbug.png')
img(figsize = (4,4))
plt.imshow(img)
jupyter notebook是一种基于 JSON 的文档格式 .ipynb, 这种格式是的我们可以轻松分享代码,分析结果,特别是展示图标。目前在各种 Python 研讨会上,一种流行的演示手段就是使用 IPython Notebook,然后再讲 .ipynb 文件发布到网上供所有人参考。
Jupyter Notebook 是一个运行于命令行上的轻量级服务器进程。执行下面代码即可启动
In [ ]:
jupyter notebook
如果想要图标以inline方式展示,可以在打开notebook后加入 %matplotlib --inline 或者 %pylab --inline
In [ ]:
import some_lib
x = 4
y = [1,34,5,6]
result = some_lib.get_answer(x,y)
如果在执行了 %run sample_script.py 后又对 some_lib.py 进行了修改,下次再执行 %run sample_script.py 时候,将仍然会使用老版本的some_lib。其原因在于python是一种“一次加载”系统。不像 matplab等,它会自动应用代码修改。
那么怎么解决这个问题呢?
第一个办法是使用内置的reload函数,即将 sample_script.py 修改成
In [ ]:
import some_lib
reload(some_lib)
x = 4
y = [1,34,5,6]
result = some_lib.get_answer(x,y)
这样,就可以保证每次执行 sample_script.py 时候都能使用最新的 some_lib 了。不过这个办法有个问题,当依赖变得更强时,就需要在很多地插入 reload.
第二个办法可以弥补上述第一个办法的弊端。IPython 提供了一个特殊的 dreload 函数 (非魔术函数) 来解决模块的“深度”重加载。如果执行 import some_lib 之后在输入 derealod(some_lib),则它会尝试重新加载 some_lib 及其所有的依赖项。遗憾的是,这个办法也不是“屡试不爽”的,但倘若失效的,重新启动 IPython 就可以解决所有加载问题。
In [1]:
import this
In [4]:
class Message:
def __init__(self, msg):
self.msg = msg
如果像下面这样写,我们会发现这个类的默认输出很不好看:
In [5]:
x = Message('I have secret')
In [6]:
x
Out[6]:
由于IPython会获取repr方法返回的字符串(具体方法是 output = repr(obj)),并将其显示到控制台上。因此,我们可以为上面那个类添加一个简单的 repr 方法以得到一个更有意义的输出形式:
In [11]:
class Message:
def __init__(self,msg):
self.msg = msg
def __repr__(self):
return('Message: %s' % self.msg)
In [12]:
x = Message('I have a secret')
In [13]:
x
Out[13]:
IPython shell 在外观和行为方面的大部分内容都是可以进行配置的。下面是能够通过配置做的部分事情:
修改颜色方案
修改输入输出提示符
去掉 out 提示符跟下一个 In 提示符之间的空行
执行任意 Python 语句。这些语句可以用于引入所有常用的东西,还可以做一些你希望每次启动 IPython 都发生的事情。
启用 IPython 扩展,如 line_profiler 中的魔术命令 %lprun
定义我们自己的魔术命令或者系统别名
所有这些设置都在一个叫做 ipython_config.py 的文件中,可以在 ~/.config/ipython 目录中找到。Linux和windows系统目录略有点小区别。对于我自己来说,我在git bash on windows 上的目录是:~/.ipython/profile_default/ipython_config.py
一个实用的功能是,利用 ipython_config.py,我们可以拥有多个个性化设置。假设我们想专门为某个特定程序或者项目量身定做 IPython 配置。输入下面这样的命令即可新建一个新的个性化配置文件:
In [ ]:
ipython profile create secret_project
#这会创建一个新的配置文件,目录在 :~/.ipython/profile_secret_project/ipython_config.py
然后编辑新建的这个 profile_secret_project 中的配置文件,再用如下方式启动它:
In [ ]:
ipython --profile=secret_project