<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 阅读笔记
 作者：方跃文 
 Email
Step1:  Tab 键自动完成
在python shell中，输入表达式时候，只要按下Tab键，当前命名空间中任何已输入的字符串相匹配的变量（对象、函数等）就会被找出来：
Step2:  此外，我们还可以在任何对象之后输入一个句点来方便地补全方法和属性的输入：
Step3:  Tab键自动完成成功不只可以搜索命名空间和自动完成对象或模块属性。当我们输入任何看上去像文件路径的东西时（即便是在一个Python字符串中），按下Tab键即可找出电脑文件系统中与之匹配的东西。
Step4:  内省
在变量的前面或者后面加上一个问号就可以将有关该对象的一些通用信息显示出来，这个就是内省，即object introspection.
Step6:  上面执行完，jupyter会跳出一个小窗口并且显示如下：
Type
Step7:  ?还有一个用法，即搜索IPython的命名空间，类似于标准UNIX或者Windows命令行中的那种用法。一些字符再配以通配符即可显示出所有与该通配符表达式相匹配的名称。例如我们可以列出NumPy顶级命名空间中含有“load"的所有函数。
Step8:  上述执行后，jupyter notebooK会给出：
np.loader
np.load
np.loads
np.loadtxt
np.pkgload
%run命令
在IPython会话中，所有文件都可以通过%run命令当作Python程序来运行。假设当前目录下的chapter03文件夹中有个simple01.py的脚本，其中内容为
Step9:  上述脚本simple01.py是在一个空的命名空间中运行的，没有任何import，也没有定义任何其他的变量，所以其行为跟在命令行运行是一样的。此后，该脚本中所定义的变量(包括脚本中的import、函数、全局变量)就可以在当前jupyter notebook中进行访问（除非有其他错误或则异常）
Step10:  如果Python脚本中需要用到命令行参数（通过 sys.argv访问），可以将参数放到文件路径的后面，就像在命令行执行那样。
  如果希望脚本执行的时候会访问当前jupyter notebook中的变量，应该用…%run -i script.py，例如
我在chapter03文件夹中写下
x = 32
add = x + result
print('add is %d' % (add))
Step11:  中断执行的代码
任何代码在执行时候（无论是通过%run执行的脚本还是长时间运行的命令），只要按下按下“Ctrl+C”,就会引发一个keyboardInterrupt。出一些特殊的情况之外，绝代分python程序都将因此立即停止执行。
例如：
当python代码已经调用了某个已编译的扩展模块时，按下Ctrl+C将无法立即停止执行。
在这种情况下，要么需要等待python解释器重新获得控制权，要么只能通过
操作系统的任务管理器强制执行终止python进程。
执行剪贴板中的代码
在IPython shell（注意，我这里强调一下，并不是在jupyter notebook中，而是ipython shell,虽然我有时候
把他们两个说的好像等效一样，但是两者还是不同的）中执行代码的最简单方式就是粘贴剪贴板中的代码。虽然这种做法很粗糙，
但是在实际工作中就很有用。比如，在开发一个复杂或耗时的程序时候，我们可能需要一段
一段地执行脚本，以便查看各个阶段所加载的数据以及产生的结果。又比如说，在网上找到了
一个何用的代码，但是又不想专门为其新建一个.py文件。
多数情况下，我们可以通过“Ctrl-Shift-V”将粘贴版中的代码片段粘贴出来(windows中)。
%paste 和 %cpaste 这两个魔术函数可以粘贴剪贴板中的一切文本。在ipython shell中这两个函数
可以帮助粘贴。后者%cpaste相比于%paste只是多了粘贴代码的特殊提示符，可以一行一行粘贴。
Step12:  IPython 跟编辑器和IDE之间的交互
某些文本编辑器（EMACS, VIM）带有一些能将代码块直接发送到ipython shell的第三方扩展。某些IDE中也
预装有ipython。
对于我自己而言，我喜欢用git bash，然后在里面折腾vim. 当然我有时候也用IDE
键盘快捷键
IPython提供了许多用于提示符导航（Emacs文本编辑器或者UNIX bash shell的用户对此会很熟悉）和查阅历史shell命令的快捷键。因为我不喜欢在ipython shell中写code，所以我就跳过了。如果有人读到我的笔记发现这里没有什么记录的话请自行查找原书。
异常和跟踪
如果%run某段脚本或执行某条语句发生了一场，IPython默认会输出整个调用栈跟踪traceback，其中还会附上调用栈各点附近的几行代码作为上下文参考。
Step13:  拥有额外的上下文代码参考是它相对于标准python解释器的一大优势。上下文代码参考的数量可以通过%mode魔术命令进行控制，既可以少（与标准python解释器相同）也可以多（带有函数参数值以及其他信息）。本章后面还会讲到如果在出现异常之后进入跟踪栈进行交互式的事后调试post-mortem debugging.
魔术命令
IPython有一些特殊命令（魔术命令Magic Command)，它们有的为常见任务提供便利，有的则使你能够轻松控制IPtython系统的行为。魔术命令是以百分号%为前缀的命令。例如，我们可以通过 %timeit 这个魔术命令检测任意Python语句（如矩阵乘法）的执行时间（稍后对此进行详细讲解）：
Step14:  魔术命令可以看作运行于IPython系统中的命令行程序。它们大都还有一些“命令行”，使用“？”即可查看其选项
Step15:  上面执行后，会跳出它的docstring
Step16:  常用的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中的对象上的一切引用 |
基于Qt的富GUI控制台
IPython团队开发了一个基于Qt框架（其摩的是为终端应用程序提供诸如内嵌图片、多行编辑、语法高亮之类的富文本编辑功能）的GUI控制平台。如果你已经安装了PyQt或者Pyside，使用下面命令来启动的话即可为其添加绘图功能。
ipython qtconsole --pylab=inline
Qt控制台可以通过标签页的形式启动多个IPython进程，这就使得我们可以在多个任务之间轻松地切换。它也开业跟IPython HTML Notebote （即我现在用的jupyter noteboo)共享同一个进程，稍后我们对此进行演示说明。
matplotlib 集成与pylab模式
导致Ipython广泛应用于科学计算领域的部分原因是它跟matplotlib这样的库以及GUI工具集默契配合。
通常我们通过在启动Ipython时候添加--pylab标记来集成matplotlib
Step17:  上述的操作会导致几个结果：
IPython 会启动默认GUI后台集成，这样matplotib绘图窗口创建就不会出现问题；
Numpy和matplotlib的大部分功能会被引入到最顶层的interactive命名空间以产生一个交互式的计算环境（类似matlab等）。也可以通过%gui对此进行手工设置（详情请执行%gui?）
Step18:  使用命令历史
IPython 维护着一个位于硬盘上的小型数据库。其中含有你执行过的每条命令的文本。这样做有几个目的：
只需很少的按键次数即可搜索、自动完成并执行之前已经执行过的命令
在会话间持久化历史命令
将输入/输出历史纪录到日志中去
搜索并重用命令历史
IPython倡导迭代、交互的开发模式：我们常常发现自己总是重复一些命令，假设我们已经执行了
Step19:  如果我们想在修改了simple01.py（当然也可以不改）后再次执行上面的操作，只需要输入 %run 命令的前几个字符并按下“ctrl+P”键或者向上箭头就会在命令历史的第一个发现它. (可能是因为我用的是git bash on windows,我自己并未测试成功书中的这个操作;但是在Linux中，我测试是有效的)。此外，ctrl-R可以实现部分增量搜索，跟Unix shell中的readline所提供的功能一样,并且ctrl-R将会循环搜索命令历史中每一条与输入相符的行。
例如，第一次ctrl-R后，我输入了c，ipython返回给我的是：
In [6]
Step20:  输入的文本被保存在名为 _iX 的变量中，其中X是输入行的行号。每个输入变量都有一个对应的输出变量 _X。例如：
Step21:  由于输入变量是字符串，因此可用python的exec关键字重新执行
Step22:  %reset 用于清空 interactive 命名空间，并可选择是否清空输入和输出缓存。%xdel 用于从IPython系统中移除特定对象的一切引用。
Step23:  注意：在处理大数据集时，需注意IPython的输入和输出历史，它会导致所有对象引用都无法被垃圾收集器处理（即释放内存），即使用del关键字将变量从interactive命名空间中删除也不行。对于这种情况，谨慎地使用%xdel和%reset将有助于避免出现内存方面的问题。
记录输入和输出
IPython能够记录整个控制台会话，包括输入和输出。执行 %logstart 即可开始记录日志
Step24:  IPython的日志功能开在任何时刻开气，以便记录整个会话。%logstart的具体选项可以参考帮助文档。此外还可以看看几个与之配套的命令：%logoff, %logon, %logstate, 以及 %logstop
Step25:  与操作系统交互
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形式返回系统环境变量 |
shell 命令和别名
在 IPython 中，以感叹号开头的命令行表示其后的所有内容需要在系统shell中执行。In other words, 我们可以删除文件（如rm或者del）、修改目录或执行任意其他处理过程。甚至我们还可启动一些将控制权从IPython手中夺走的进程（比如另外再启动一个Python解释器）：
yang@comet-1.edu  ~ 19
Step26:  在使用！时，IPython 还允许使用当前环境中定义的python值。只需在变量名前面加上美元符号（$）即可：
Step27:  魔术命令 %alias 可以为shell命令自定义简称。例：
In [3]
Step28:  定义好之后就可以在ipython shell(或jupyter notebook)中使用魔术命令%cd db来使用这些标签
如果书签的名字与当前工作目录中某个名字冲突时，可通过 -b 标记（起作用是覆写）使用书签目录。%bookmark的 -l 选项的作用是列出所有书签。
Step29:  软件开发工具
IPython 不仅是交互式环境和数据分析环境，同时也非常适合做开发环境。在数据分析应用程序中，最重要的是要拥有正确的代码。IPython继承了Python内置的  pdb  调试器。 此外，IPython 提供了一些简单易用的代码运行时间以及性能分析的工具。
交互式调试器
IPython的调试器增加了  pdb ，如 Tab 键自动完成、语法高亮、为异常跟踪的每条信息添加上下文参考等。调试代码的最佳时机之一就是错误刚发生的时候。 %debug 命令（在发生异常之后立即输入）将会条用那个“时候”调试器，并直接跳转到发生异常的那个 栈帧  （stack frame）
Step30:  在这个 pdb 调试器中，我们可以执行任意Python 代码并查看各个栈帧中的一切对象和数据，这就相当于解释器还留了条后路给我们。默认是从最低级开始的，即错误发生的地方，在上面ipdb>后面输入u (up) 或者 d (down) 即可在栈跟踪的各级别之间进行切换。
Step31:  此外调试器还能为代码开发提供帮助，尤其当我们想设置断点或者对函数/脚本进行单步调试时。实现这个目的的方式如下所述。
用带有 -d 选项的 %run 命令，这将会在执行脚本文件中的代码之前先打开调试器。必须立即输入 s（或step）才能进入脚本：
Step32:  在此之后，上述文件执行的方式就全凭我们自己说了算了。比如说，在上面那个异常中，我们可以在调用 works_fine 方法的地方设置一个断点，然后输入 c (或者 continue) 使脚本一直运行下去直到该断点时为止。
Step33:  如果想精通这个调试器，必须经过大量的实践。
虽然大部分 IDE 都会自带调试器，但是 IPython 中调试程序的方法往往会带来更高的生产率。
下面是常用的 IPython 调试器命令
|命令 | 功能 |
|------| ------|
| h(elp) | 显示命令列表 |
| help command | 显示 command 的文档 |
| c(ontinue) | 恢复程序的执行 |
| q(uit) | 推出调试器，不再执行任何代码 |
| b(reak) number | 在当前文件的第 number 行设置一个断点 |
| b path/to/file.py
Step34:  测试代码执行的时间： %time 和 %timeit
对于大规模数据分析，我们有时候需要对时间有个规划和预测。特别是对于其中最耗时的函数。IPython中可以轻松应对这种情况。
使用内置的 time 模块，以及 time.clock 和 time.time 函数 手工测试代码执行时间是令人烦闷的事情，因为我们必须编写许多一样的公式化代码：
Step35:  由于这是一个非常常用的功能，所以IPython提供了两个魔术工具 %time 和 %timeit 来自动完成该过程。%time 一次执行一条语句，然后报告总的执行时间。假设我们有一大堆字符串，希望对几个“能选出具有特殊前缀的字符串”的函数进行比较。下面是一个拥有60万字字符串的数组，以及两个不同的“能够选出其中以foo开头的字符串”的方法：
Step36:  Wall time是我们感兴趣的数字。所以，看上去第一个方法耗费了接近2倍的时间，但是这并非一个非常精确的结果。如果我们队相同语句多次执行%time的话，就会发现其结果是变化的。为了得到更加精确的结果，我们需要使用魔术函数 %timeit。对于任意语句，它会自动多次执行以产生一个非常精确的平均执行时间
Step37:  这个很平淡无奇的离子告诉我们这样一个道理：我们有必要了解Python标准库、Numpy、Pandas 以及 本书所用其他库的性能特点。在大型数据分析中，这些不起眼的毫秒数会不断累积产生蝴蝶效应。
对于那些执行时间非常短（甚至是微妙 1e-6 s；或者 纳秒 1e-9 s）的分析语句和函数而言，%timeit 是非常有用的。虽然对于单次执行而言，这些时间小到几乎可以忽略不计。但是我们只要举一个例子，就会发现我们很有必要“分秒必争”：
同样执行100万次一个20微妙的函数，所化时间要比一个5微妙的多出15秒。
在上面我运行的那个例子中，我们可以直接对两个字符串运算进行比较，以了解其性能特点：
Step38:  基本性能分析
Step39:  我们将上述脚本内容写入 simple03.py (目录为当前目录下的chapter03目录中），并且执行
Step40:  即使这里不明白脚本里面具体做的事情，那也没有关系，反正先这么照着书里先做着，感受下cProfile的作用。
我们可以看到，输出结果是按照函数名排序的(ordered by standard name)。这样就比较难看出哪些地方是最花时间的，因此通常用 -s 标记，换一种排序的规则：
Step41:  我们看到此时的排序规则为 Ordered by
Step42:  在ipython terminal中，执行 %run -p -s cumulative chapter03/simple03.py也能达到上述效果，但是却无法退出IPython。
逐行分析函数性能
有时候，%prun （或者其他基于cProfile的性能分析手段）所得到的信息要么不足以说明函数的执行时间，要么难以理解（按函数名聚合?）。对于这种情形，我们可以使用一个叫做line_profiler的小型库。气质有一个心的魔术函数 %lprun， 它可以对一个或者多个函数进行逐行性能分析。我们有修改 IPython 配置 以启用这个扩展.
For IPython 0.11+, you can install it by editing the IPython configuration file ~/.ipython/profile_default/ipython_config.py to add the 'line_profiler' item to the extensions list
Step43:  line_profiler 可以通过编程方式使用，但是其更强大的一面在于与 Ipython 的交互使用。
假设我们有一个名为 prof_mod 的模块，其代码内容为（我们把prof_mode.py 保存在 chapter03目录下）
Step44:  如果我们想了解 add_and_sum 函数的性能，%prun 会给出如下所示的结果
Step45:  执行的结果为：
当我们启用 line_profiler 这个扩展后，就会出现新的魔术命令 %lprun。 用法上唯一的区别就是： 必须为 %lprun 指明想要测试哪个或哪些函数。%lprun 的通用语法为：
Step46:  在本例子中，我们想要测试 add_and_sum，于是执行
Step47:  网上找了下别人也遇到了和我一样的错误，stackoverflow上面有解决方案：
Step48:  然后我们再执行一次
Step49:  这个结果就容易理解了许多。这里我们测试的只是 add_and_sum 这个函数。上面那个模块中还有一个call_function 函数，我们可以结合 add_and_sum 一起测试，于是最终我们的命令成为了这个样子：
Step50:  通常我们会用 %prun （cProfile） 做宏观性能分析，而用 %lprun 来做 微观的性能分析。
 注意，在使用 %lprun 时，之所以必须显示指明待测试函数的函数名，是因为“跟踪”每一行代码的时间代价是巨大的。对不感兴趣的函数进行跟踪会对分析结果产生很显著的影响。
IPython HTML Notebook
IPthon HTML Notebook，即现在的 jupyter notebook。这个其实在我整个笔记中都已经在使用了。notebook项目最初由 Brian Graner 领导的 Ipython 团队从 2011 年开始开发。目前已被广泛使用于开发和数据分析。
首先来看个导入图标的例子，其实这个笔记的开头，我也已经展示过部分这样的功能
Step51:  此处补充一个书上 导入图片的一个例子：
Step52:  jupyter notebook是一种基于 JSON 的文档格式 .ipynb， 这种格式是的我们可以轻松分享代码，分析结果，特别是展示图标。目前在各种 Python 研讨会上，一种流行的演示手段就是使用 IPython Notebook，然后再讲 .ipynb 文件发布到网上供所有人参考。
Jupyter Notebook 是一个运行于命令行上的轻量级服务器进程。执行下面代码即可启动
Step53:  如果想要图标以inline方式展示，可以在打开notebook后加入 %matplotlib --inline 或者 %pylab --inline
利用IPython 提高代码开发效率的几点提示
使用 IPython，可以让代码的结果更容易交互和亦欲查看。特别是当执行出现错误的时候，IPython 的交互性可以带来极大的便利
重新加载模块依赖项
在 Python 中，当我们输入 import some_lib 时候，some_lib 中的代码就会被执行，且其中所有的变量、函数和引入项都会保存在一个新建立的 some_lib 模块命名空间中。下次再输入 import some_lib 时，就会得到这个模块命名空间的一个引用。而这对于 IPython 的交互式代码开发模式就会有一个问题。
比如，用 %run 执行的某段脚本中包含了某个刚刚做了修改的模块。假设我们有一个 sample_script.py 文件，其中有如下代码：
Step54:  如果在执行了 %run sample_script.py 后又对 some_lib.py 进行了修改，下次再执行 %run sample_script.py 时候，将仍然会使用老版本的some_lib。其原因在于python是一种“一次加载”系统。不像 matplab等，它会自动应用代码修改。
那么怎么解决这个问题呢？
第一个办法是使用内置的reload函数，即将 sample_script.py 修改成
Step55:  这样，就可以保证每次执行 sample_script.py 时候都能使用最新的 some_lib 了。不过这个办法有个问题，当依赖变得更强时，就需要在很多地插入 reload.
第二个办法可以弥补上述第一个办法的弊端。IPython 提供了一个特殊的 dreload 函数 （非魔术函数） 来解决模块的“深度”重加载。如果执行 import some_lib 之后在输入 derealod(some_lib),则它会尝试重新加载 some_lib 及其所有的依赖项。遗憾的是，这个办法也不是“屡试不爽”的，但倘若失效的，重新启动 IPython 就可以解决所有加载问题。
代码设计提示
作者说这个问题不好讲，但是他在日常生活中的确发现了一些高层次的原则。
保留有意义的对象和数据
扁平结构要比嵌套结构好：嵌套结构犹如洋葱，想要调试需要剥掉好多层。(这种思想源自于Zen of Python by Tim Peters. 在jupyter notebook中输入 import this可以看到这首诗)
无惧大文件。这样可以减少模块的反复加载，编辑脚本时候也可以减少跳转。维护也更加方便。维护更大的模块会更实用且更加符合python的特点。
Step56:  高级python功能
让你的类对IPython更加友好
IPython 力求为各种对象呈现一个友好的字符串表示。对于许多对象（如字典、列表、组等），内置的pprint 模块就能给出漂亮的格式。但是对于我们自己所定义的那些类，必须自己格式化进行输出。假设我们以后下面这个简单的类：
Step57:  如果像下面这样写，我们会发现这个类的默认输出很不好看：
Step58:  由于IPython会获取__repr__方法返回的字符串（具体方法是 output = repr(obj)），并将其显示到控制台上。因此，我们可以为上面那个类添加一个简单的 repr 方法以得到一个更有意义的输出形式：
Step59:  个性化和配置
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 配置。输入下面这样的命令即可新建一个新的个性化配置文件：
Step60:  然后编辑新建的这个 profile_secret_project 中的配置文件，再用如下方式启动它：
<ASSISTANT_TASK:>
Python Code:
a = 5
a
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)
Explanation: 阅读笔记
 作者：方跃文 
 Email: fyuewen@gmail.com 
 时间：始于2017年9月12日 
 第三章笔记始于2017年9月28日23:38，结束于 2017年10月17日 
第三章 IPtyhon: 一种交互式计算和开发环境
IPython鼓励一种“执行探索——execute explore”精神，这就区别于传统的“编辑——编译——执行 edit——complie——run”
IPython 基础
End of explanation
an_apple = 27
an_example = 42
an_ #按下tab键就会看到之前定义的变量会被显示出来，方便我们做出选择。
Explanation: Tab 键自动完成
在python shell中，输入表达式时候，只要按下Tab键，当前命名空间中任何已输入的字符串相匹配的变量（对象、函数等）就会被找出来：
End of explanation
import IPython
print(IPython.sys_info())
a = [1,2,3]
a.append(0)
a
import datetime
dt = datetime.time(22,2,2)
dd = datetime.date(2017,2,2)
print("%s %s" % (dt,dd))
Explanation: 此外，我们还可以在任何对象之后输入一个句点来方便地补全方法和属性的输入：
End of explanation
./  #按下Tab键， 如果你当前目录下有文件或者目录，会给出提示。
Explanation: Tab键自动完成成功不只可以搜索命名空间和自动完成对象或模块属性。当我们输入任何看上去像文件路径的东西时（即便是在一个Python字符串中），按下Tab键即可找出电脑文件系统中与之匹配的东西。
End of explanation
b=[1,2,3]
    
b?
Explanation: 内省
在变量的前面或者后面加上一个问号就可以将有关该对象的一些通用信息显示出来，这个就是内省，即object introspection.
End of explanation
def add_numbers(a,b):
    #引号部分则为docstring
    
    Add two numbers together
    
    Returns
    -------
    the_sum: type of arguments
    
    
    return a+b
add_numbers(1,2)
add_numbers?
#加一个问号执行会显示上述我已经编写好的docstring，这样在忘记函数作用的时候还是很不错的功能。
add_numbers??
#加两个问号则会显示该函数的源代码
Explanation: 上面执行完，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(如果有的话)也会显示出来。例如：
End of explanation
import numpy as np
np.*load*?
Explanation: ?还有一个用法，即搜索IPython的命名空间，类似于标准UNIX或者Windows命令行中的那种用法。一些字符再配以通配符即可显示出所有与该通配符表达式相匹配的名称。例如我们可以列出NumPy顶级命名空间中含有“load"的所有函数。
End of explanation
def f(x,y,z):
    return (x+y)/z
a=5
b=6
c=8
result = f(a,b,c)
print(result)
#执行
%run ./chapter03/simple01.py
Explanation: 上述执行后，jupyter notebooK会给出：
np.loader
np.load
np.loads
np.loadtxt
np.pkgload
%run命令
在IPython会话中，所有文件都可以通过%run命令当作Python程序来运行。假设当前目录下的chapter03文件夹中有个simple01.py的脚本，其中内容为
End of explanation
result
Explanation: 上述脚本simple01.py是在一个空的命名空间中运行的，没有任何import，也没有定义任何其他的变量，所以其行为跟在命令行运行是一样的。此后，该脚本中所定义的变量(包括脚本中的import、函数、全局变量)就可以在当前jupyter notebook中进行访问（除非有其他错误或则异常）
End of explanation
%run -i ./chapter03/simple02.py  #-i即interactive
Explanation: 如果Python脚本中需要用到命令行参数（通过 sys.argv访问），可以将参数放到文件路径的后面，就像在命令行执行那样。
  如果希望脚本执行的时候会访问当前jupyter notebook中的变量，应该用…%run -i script.py，例如
我在chapter03文件夹中写下
x = 32
add = x + result
print('add is %d' % (add))
End of explanation
#下面我把我在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.
Explanation: 中断执行的代码
任何代码在执行时候（无论是通过%run执行的脚本还是长时间运行的命令），只要按下按下“Ctrl+C”,就会引发一个keyboardInterrupt。出一些特殊的情况之外，绝代分python程序都将因此立即停止执行。
例如：
当python代码已经调用了某个已编译的扩展模块时，按下Ctrl+C将无法立即停止执行。
在这种情况下，要么需要等待python解释器重新获得控制权，要么只能通过
操作系统的任务管理器强制执行终止python进程。
执行剪贴板中的代码
在IPython shell（注意，我这里强调一下，并不是在jupyter notebook中，而是ipython shell,虽然我有时候
把他们两个说的好像等效一样，但是两者还是不同的）中执行代码的最简单方式就是粘贴剪贴板中的代码。虽然这种做法很粗糙，
但是在实际工作中就很有用。比如，在开发一个复杂或耗时的程序时候，我们可能需要一段
一段地执行脚本，以便查看各个阶段所加载的数据以及产生的结果。又比如说，在网上找到了
一个何用的代码，但是又不想专门为其新建一个.py文件。
多数情况下，我们可以通过“Ctrl-Shift-V”将粘贴版中的代码片段粘贴出来(windows中)。
%paste 和 %cpaste 这两个魔术函数可以粘贴剪贴板中的一切文本。在ipython shell中这两个函数
可以帮助粘贴。后者%cpaste相比于%paste只是多了粘贴代码的特殊提示符，可以一行一行粘贴。
End of explanation
%run ./pydata-book/ch03/ipython_bug.py
Explanation: IPython 跟编辑器和IDE之间的交互
某些文本编辑器（EMACS, VIM）带有一些能将代码块直接发送到ipython shell的第三方扩展。某些IDE中也
预装有ipython。
对于我自己而言，我喜欢用git bash，然后在里面折腾vim. 当然我有时候也用IDE
键盘快捷键
IPython提供了许多用于提示符导航（Emacs文本编辑器或者UNIX bash shell的用户对此会很熟悉）和查阅历史shell命令的快捷键。因为我不喜欢在ipython shell中写code，所以我就跳过了。如果有人读到我的笔记发现这里没有什么记录的话请自行查找原书。
异常和跟踪
如果%run某段脚本或执行某条语句发生了一场，IPython默认会输出整个调用栈跟踪traceback，其中还会附上调用栈各点附近的几行代码作为上下文参考。
End of explanation
import numpy as np
from numpy.random import randn
a = randn(3,3,3)
a
%timeit np.dot(a,a)
Explanation: 拥有额外的上下文代码参考是它相对于标准python解释器的一大优势。上下文代码参考的数量可以通过%mode魔术命令进行控制，既可以少（与标准python解释器相同）也可以多（带有函数参数值以及其他信息）。本章后面还会讲到如果在出现异常之后进入跟踪栈进行交互式的事后调试post-mortem debugging.
魔术命令
IPython有一些特殊命令（魔术命令Magic Command)，它们有的为常见任务提供便利，有的则使你能够轻松控制IPtython系统的行为。魔术命令是以百分号%为前缀的命令。例如，我们可以通过 %timeit 这个魔术命令检测任意Python语句（如矩阵乘法）的执行时间（稍后对此进行详细讲解）：
End of explanation
%reset?
Explanation: 魔术命令可以看作运行于IPython系统中的命令行程序。它们大都还有一些“命令行”，使用“？”即可查看其选项
End of explanation
a = 1
a
'a' in _ip.user_ns  # 不知道为什么这里没有执行通过？
%reset -f
'a' in __ip.user__ns
Explanation: 上面执行后，会跳出它的docstring
End of explanation
#在terminal 输入
ipython --pylab
#回显中会出现部分关于matplotlib的字段
#IPython 6.2.0 -- An enhanced Interactive Python. Type '?' for help.
#Using matplotlib backend: Qt5Agg
Explanation: 常用的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中的对象上的一切引用 |
基于Qt的富GUI控制台
IPython团队开发了一个基于Qt框架（其摩的是为终端应用程序提供诸如内嵌图片、多行编辑、语法高亮之类的富文本编辑功能）的GUI控制平台。如果你已经安装了PyQt或者Pyside，使用下面命令来启动的话即可为其添加绘图功能。
ipython qtconsole --pylab=inline
Qt控制台可以通过标签页的形式启动多个IPython进程，这就使得我们可以在多个任务之间轻松地切换。它也开业跟IPython HTML Notebote （即我现在用的jupyter noteboo)共享同一个进程，稍后我们对此进行演示说明。
matplotlib 集成与pylab模式
导致Ipython广泛应用于科学计算领域的部分原因是它跟matplotlib这样的库以及GUI工具集默契配合。
通常我们通过在启动Ipython时候添加--pylab标记来集成matplotlib
End of explanation
#原书给了一个在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')
plt.imshow(img)
#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)
%matplotlib inline
import matplotlib.pylab as plab
from numpy.random import randn
plab.plot(randn(1000).cumsum())
Explanation: 上述的操作会导致几个结果：
IPython 会启动默认GUI后台集成，这样matplotib绘图窗口创建就不会出现问题；
Numpy和matplotlib的大部分功能会被引入到最顶层的interactive命名空间以产生一个交互式的计算环境（类似matlab等）。也可以通过%gui对此进行手工设置（详情请执行%gui?）
End of explanation
#在ipython terminal执行
%run chapter03/simple01.py
Explanation: 使用命令历史
IPython 维护着一个位于硬盘上的小型数据库。其中含有你执行过的每条命令的文本。这样做有几个目的：
只需很少的按键次数即可搜索、自动完成并执行之前已经执行过的命令
在会话间持久化历史命令
将输入/输出历史纪录到日志中去
搜索并重用命令历史
IPython倡导迭代、交互的开发模式：我们常常发现自己总是重复一些命令，假设我们已经执行了
End of explanation
a=3
a
b=4
b
__
c=5
c
_
Explanation: 如果我们想在修改了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中，最近的两个输出分别保存在 _ 和 __ 两个变量中
End of explanation
foo = 'bar'
foo
_i9
_9
Explanation: 输入的文本被保存在名为 _iX 的变量中，其中X是输入行的行号。每个输入变量都有一个对应的输出变量 _X。例如：
End of explanation
%hist
Explanation: 由于输入变量是字符串，因此可用python的exec关键字重新执行: exec _i9
有几个魔术命令可用于输入、输出历史。%hist用于打印全部或部分历史，可以选择是否带行号
End of explanation
%reset
a #由于上面已经清理了命名空间，所以python并不知道a是多少。
Explanation: %reset 用于清空 interactive 命名空间，并可选择是否清空输入和输出缓存。%xdel 用于从IPython系统中移除特定对象的一切引用。
End of explanation
%logstart
Explanation: 注意：在处理大数据集时，需注意IPython的输入和输出历史，它会导致所有对象引用都无法被垃圾收集器处理（即释放内存），即使用del关键字将变量从interactive命名空间中删除也不行。对于这种情况，谨慎地使用%xdel和%reset将有助于避免出现内存方面的问题。
记录输入和输出
IPython能够记录整个控制台会话，包括输入和输出。执行 %logstart 即可开始记录日志
End of explanation
%logstart?
Explanation: IPython的日志功能开在任何时刻开气，以便记录整个会话。%logstart的具体选项可以参考帮助文档。此外还可以看看几个与之配套的命令：%logoff, %logon, %logstate, 以及 %logstop
End of explanation
In [4]: my_current_dir = !pwd
In [5]: my_current_dir
Out[5]: ['/home/ywfang']
返回的python对象my_current_dir实际上是一个含有控制台输出结果的自定义列表类型。
Explanation: 与操作系统交互
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形式返回系统环境变量 |
shell 命令和别名
在 IPython 中，以感叹号开头的命令行表示其后的所有内容需要在系统shell中执行。In other words, 我们可以删除文件（如rm或者del）、修改目录或执行任意其他处理过程。甚至我们还可启动一些将控制权从IPython手中夺走的进程（比如另外再启动一个Python解释器）：
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中
End of explanation
#在ipython shell中
In [1]: foo = 'note*'
In [2]: !ls $foo
notebook.log
Explanation: 在使用！时，IPython 还允许使用当前环境中定义的python值。只需在变量名前面加上美元符号（$）即可：
End of explanation
%bookmark db D:\PhDinECNU #windows中的写法；如果是Linux，应该为/d/PhDinECNU/
%bookmark dt D:\temp
%cd db
Explanation: 魔术命令 %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会在会话结束时立即"忘记"我们前面所定义的一切别名。如果要进行永久性的别名设置，需要使用配置系统。之后会进行介绍。
目录书签系统
IPython 有一个简单的目录书签系统，它使我们能保存常用目录的别名以便方便地快速跳转。比如，作为一个狂热的dropbox用户，为了能够快速地转到dropbox目录，可以定义一个书签：
End of explanation
%bookmark -l
Explanation: 定义好之后就可以在ipython shell(或jupyter notebook)中使用魔术命令%cd db来使用这些标签
如果书签的名字与当前工作目录中某个名字冲突时，可通过 -b 标记（起作用是覆写）使用书签目录。%bookmark的 -l 选项的作用是列出所有书签。
End of explanation
%reset
%cd D:\PhDinECNU\readingnotes\readingnotes\machine-learning\McKinney-pythonbook2013
%run pydata-book/ch03/ipython_bug.py
%debug
Explanation: 软件开发工具
IPython 不仅是交互式环境和数据分析环境，同时也非常适合做开发环境。在数据分析应用程序中，最重要的是要拥有正确的代码。IPython继承了Python内置的  pdb  调试器。 此外，IPython 提供了一些简单易用的代码运行时间以及性能分析的工具。
交互式调试器
IPython的调试器增加了  pdb ，如 Tab 键自动完成、语法高亮、为异常跟踪的每条信息添加上下文参考等。调试代码的最佳时机之一就是错误刚发生的时候。 %debug 命令（在发生异常之后立即输入）将会条用那个“时候”调试器，并直接跳转到发生异常的那个 栈帧  （stack frame）
End of explanation
执行%pdb命令可以让IPython在出现异常之后直接调用调试器，很多人都认为这一功能很实用。
Explanation: 在这个 pdb 调试器中，我们可以执行任意Python 代码并查看各个栈帧中的一切对象和数据，这就相当于解释器还留了条后路给我们。默认是从最低级开始的，即错误发生的地方，在上面ipdb>后面输入u (up) 或者 d (down) 即可在栈跟踪的各级别之间进行切换。
End of explanation
%run -d ./pydata-book/ch03/ipython_bug.py
Explanation: 此外调试器还能为代码开发提供帮助，尤其当我们想设置断点或者对函数/脚本进行单步调试时。实现这个目的的方式如下所述。
用带有 -d 选项的 %run 命令，这将会在执行脚本文件中的代码之前先打开调试器。必须立即输入 s（或step）才能进入脚本：
End of explanation
%run -d ./pydata-book/ch03/ipython_bug.py
Explanation: 在此之后，上述文件执行的方式就全凭我们自己说了算了。比如说，在上面那个异常中，我们可以在调用 works_fine 方法的地方设置一个断点，然后输入 c (或者 continue) 使脚本一直运行下去直到该断点时为止。
End of explanation
%run ./pydata-book/ch03/ipython_bug.py
%debug
Explanation: 如果想精通这个调试器，必须经过大量的实践。
虽然大部分 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 这个特别的函数（以 pdb.set_trace 命名），这差不多可算作一种 “穷人的断点”（意思是这种断点方式很随便，是硬编码的）。下面这两个方法可能会在我们的日常工作中排上用场（我们也可像作者一样直接将其加入IPython配置中）：
第一个函数 set_trace 很简单。我们可以将其放在代码中任何希望停下来查看一番的地方，尤其是那些发生异常的地方：
End of explanation
import time
start = time.time()
for i in range(iterations):
    #to do something
    elapsed_per = (time.time() - start ) / iterations
Explanation: 测试代码执行的时间： %time 和 %timeit
对于大规模数据分析，我们有时候需要对时间有个规划和预测。特别是对于其中最耗时的函数。IPython中可以轻松应对这种情况。
使用内置的 time 模块，以及 time.clock 和 time.time 函数 手工测试代码执行时间是令人烦闷的事情，因为我们必须编写许多一样的公式化代码：
End of explanation
# 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.
%time method1 = [x for x in strings if x.startswith('foo')]
%time method2 = [x for x in strings if x[:3]=='foo']
Explanation: 由于这是一个非常常用的功能，所以IPython提供了两个魔术工具 %time 和 %timeit 来自动完成该过程。%time 一次执行一条语句，然后报告总的执行时间。假设我们有一大堆字符串，希望对几个“能选出具有特殊前缀的字符串”的函数进行比较。下面是一个拥有60万字字符串的数组，以及两个不同的“能够选出其中以foo开头的字符串”的方法：
End of explanation
%timeit method = [ x for x in strings if x.startswith('foo')]
%timeit method = [x for x in strings if x[:0]=='foo']
Explanation: Wall time是我们感兴趣的数字。所以，看上去第一个方法耗费了接近2倍的时间，但是这并非一个非常精确的结果。如果我们队相同语句多次执行%time的话，就会发现其结果是变化的。为了得到更加精确的结果，我们需要使用魔术函数 %timeit。对于任意语句，它会自动多次执行以产生一个非常精确的平均执行时间
End of explanation
x = 'foobar'
y = 'foo'
%timeit x.startswith(y)
%timeit x[:3]==y
Explanation: 这个很平淡无奇的离子告诉我们这样一个道理：我们有必要了解Python标准库、Numpy、Pandas 以及 本书所用其他库的性能特点。在大型数据分析中，这些不起眼的毫秒数会不断累积产生蝴蝶效应。
对于那些执行时间非常短（甚至是微妙 1e-6 s；或者 纳秒 1e-9 s）的分析语句和函数而言，%timeit 是非常有用的。虽然对于单次执行而言，这些时间小到几乎可以忽略不计。但是我们只要举一个例子，就会发现我们很有必要“分秒必争”：
同样执行100万次一个20微妙的函数，所化时间要比一个5微妙的多出15秒。
在上面我运行的那个例子中，我们可以直接对两个字符串运算进行比较，以了解其性能特点：
End of explanation
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)))
Explanation: 基本性能分析: %run 和 %run -p
代码的性能分析跟代码执行时间密切关联，只是它关注的是耗费时间的位置。Python中，cProfile模块主要用来分析代码性能，它并非转为python设计。cProfile在执行一个程序代码或代码块时，会记录各函数所耗费的时间。
cProfile一般是在命令行上使用的，它将执行整个程序然后输出各个函数的执行时间。
下面，我们就给出了一个简单的例子：在一个循环中执行一些线性代数运算（即计算一个100 * 100 的矩阵的最大本征值绝对值）
End of explanation
!python -m cProfile chapter03/simple03.py
Explanation: 我们将上述脚本内容写入 simple03.py (目录为当前目录下的chapter03目录中），并且执行
End of explanation
!python -m cProfile -s cumulative chapter03/simple03.py
Explanation: 即使这里不明白脚本里面具体做的事情，那也没有关系，反正先这么照着书里先做着，感受下cProfile的作用。
我们可以看到，输出结果是按照函数名排序的(ordered by standard name)。这样就比较难看出哪些地方是最花时间的，因此通常用 -s 标记，换一种排序的规则：
End of explanation
%prun -l 7 -s cumulative run_experiment()
Explanation: 我们看到此时的排序规则为 Ordered by: cumulative time，这样我们只需要看 cumtime 列即可发现各函数所耗费的总计时间。 注意如果一个函数A调用了函数B，计时器并不会停止而重新计时。cProfile记录的是各函数调用的起始和结束时间，并依次计算总时间。
除了命令行用法外，cProfile 还可以通过编程的方式分析任意代码块的性能。IPython为此提供了一个方便的借口，即 %prun 命令和带 -p 选项的 %run。 %prun的格式跟 cProfile 的差不多，但它分析的是 Python 语句 而不是整个 .py 文件：
End of explanation
# A list of dotted module names of IPython extensions to load.
c.TerminalIPythonApp.extensions = [
    'line_profiler',
]
#这个代码可以确认 line_profiler 是否被正常的安装和load
import line_profiler
line_profiler
Explanation: 在ipython terminal中，执行 %run -p -s cumulative chapter03/simple03.py也能达到上述效果，但是却无法退出IPython。
逐行分析函数性能
有时候，%prun （或者其他基于cProfile的性能分析手段）所得到的信息要么不足以说明函数的执行时间，要么难以理解（按函数名聚合?）。对于这种情形，我们可以使用一个叫做line_profiler的小型库。气质有一个心的魔术函数 %lprun， 它可以对一个或者多个函数进行逐行性能分析。我们有修改 IPython 配置 以启用这个扩展.
For IPython 0.11+, you can install it by editing the IPython configuration file ~/.ipython/profile_default/ipython_config.py to add the 'line_profiler' item to the extensions list:
End of explanation
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)
Explanation: line_profiler 可以通过编程方式使用，但是其更强大的一面在于与 Ipython 的交互使用。
假设我们有一个名为 prof_mod 的模块，其代码内容为（我们把prof_mode.py 保存在 chapter03目录下）
End of explanation
%run chapter03/prof_mode.py
x = randn(3000, 3000) 
y = randn(3000,3000)
%prun add_and_sum(x,y) #因为我们这里只是测试 add_and_sum 这个函数，所以必须给它实参，所以上面我们给出了 x和y
Explanation: 如果我们想了解 add_and_sum 函数的性能，%prun 会给出如下所示的结果
End of explanation
%lprun -f func1 -f func2 statement_to_profile
Explanation: 执行的结果为：
当我们启用 line_profiler 这个扩展后，就会出现新的魔术命令 %lprun。 用法上唯一的区别就是： 必须为 %lprun 指明想要测试哪个或哪些函数。%lprun 的通用语法为：
End of explanation
%lprun -f add_and_sum add_and_sum(x,y)
Explanation: 在本例子中，我们想要测试 add_and_sum，于是执行
End of explanation
%load_ext line_profiler
Explanation: 网上找了下别人也遇到了和我一样的错误，stackoverflow上面有解决方案：
End of explanation
%lprun -f add_and_sum add_and_sum(x,y)
Explanation: 然后我们再执行一次
End of explanation
%lprun -f add_and_sum -f call_function call_function()
综上，当我们需要测试一个程序中的某些函数时，我们需要使用这两行代码：
%load_ext line_profiler
%lprun -f func1 -f func2 statement_to_profile
Explanation: 这个结果就容易理解了许多。这里我们测试的只是 add_and_sum 这个函数。上面那个模块中还有一个call_function 函数，我们可以结合 add_and_sum 一起测试，于是最终我们的命令成为了这个样子：
End of explanation
import numpy as np
import pandas as pd
print('hello world!')
Explanation: 通常我们会用 %prun （cProfile） 做宏观性能分析，而用 %lprun 来做 微观的性能分析。
 注意，在使用 %lprun 时，之所以必须显示指明待测试函数的函数名，是因为“跟踪”每一行代码的时间代价是巨大的。对不感兴趣的函数进行跟踪会对分析结果产生很显著的影响。
IPython HTML Notebook
IPthon HTML Notebook，即现在的 jupyter notebook。这个其实在我整个笔记中都已经在使用了。notebook项目最初由 Brian Graner 领导的 Ipython 团队从 2011 年开始开发。目前已被广泛使用于开发和数据分析。
首先来看个导入图标的例子，其实这个笔记的开头，我也已经展示过部分这样的功能
End of explanation
import numpy as np
import pandas as pd
tips = pd.read_csv('./pydata-book/ch08/tips.csv')
tips.head()
%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)
Explanation: 此处补充一个书上 导入图片的一个例子：
End of explanation
jupyter notebook 
Explanation: jupyter notebook是一种基于 JSON 的文档格式 .ipynb， 这种格式是的我们可以轻松分享代码，分析结果，特别是展示图标。目前在各种 Python 研讨会上，一种流行的演示手段就是使用 IPython Notebook，然后再讲 .ipynb 文件发布到网上供所有人参考。
Jupyter Notebook 是一个运行于命令行上的轻量级服务器进程。执行下面代码即可启动
End of explanation
import some_lib
x = 4
y = [1,34,5,6]
result = some_lib.get_answer(x,y)
Explanation: 如果想要图标以inline方式展示，可以在打开notebook后加入 %matplotlib --inline 或者 %pylab --inline
利用IPython 提高代码开发效率的几点提示
使用 IPython，可以让代码的结果更容易交互和亦欲查看。特别是当执行出现错误的时候，IPython 的交互性可以带来极大的便利
重新加载模块依赖项
在 Python 中，当我们输入 import some_lib 时候，some_lib 中的代码就会被执行，且其中所有的变量、函数和引入项都会保存在一个新建立的 some_lib 模块命名空间中。下次再输入 import some_lib 时，就会得到这个模块命名空间的一个引用。而这对于 IPython 的交互式代码开发模式就会有一个问题。
比如，用 %run 执行的某段脚本中包含了某个刚刚做了修改的模块。假设我们有一个 sample_script.py 文件，其中有如下代码：
End of explanation
import some_lib
reload(some_lib)
x = 4
y = [1,34,5,6]
result = some_lib.get_answer(x,y)
Explanation: 如果在执行了 %run sample_script.py 后又对 some_lib.py 进行了修改，下次再执行 %run sample_script.py 时候，将仍然会使用老版本的some_lib。其原因在于python是一种“一次加载”系统。不像 matplab等，它会自动应用代码修改。
那么怎么解决这个问题呢？
第一个办法是使用内置的reload函数，即将 sample_script.py 修改成
End of explanation
import this
Explanation: 这样，就可以保证每次执行 sample_script.py 时候都能使用最新的 some_lib 了。不过这个办法有个问题，当依赖变得更强时，就需要在很多地插入 reload.
第二个办法可以弥补上述第一个办法的弊端。IPython 提供了一个特殊的 dreload 函数 （非魔术函数） 来解决模块的“深度”重加载。如果执行 import some_lib 之后在输入 derealod(some_lib),则它会尝试重新加载 some_lib 及其所有的依赖项。遗憾的是，这个办法也不是“屡试不爽”的，但倘若失效的，重新启动 IPython 就可以解决所有加载问题。
代码设计提示
作者说这个问题不好讲，但是他在日常生活中的确发现了一些高层次的原则。
保留有意义的对象和数据
扁平结构要比嵌套结构好：嵌套结构犹如洋葱，想要调试需要剥掉好多层。(这种思想源自于Zen of Python by Tim Peters. 在jupyter notebook中输入 import this可以看到这首诗)
无惧大文件。这样可以减少模块的反复加载，编辑脚本时候也可以减少跳转。维护也更加方便。维护更大的模块会更实用且更加符合python的特点。
End of explanation
class Message:
    def __init__(self, msg):
        self.msg = msg
Explanation: 高级python功能
让你的类对IPython更加友好
IPython 力求为各种对象呈现一个友好的字符串表示。对于许多对象（如字典、列表、组等），内置的pprint 模块就能给出漂亮的格式。但是对于我们自己所定义的那些类，必须自己格式化进行输出。假设我们以后下面这个简单的类：
End of explanation
x = Message('I have secret')
x
Explanation: 如果像下面这样写，我们会发现这个类的默认输出很不好看：
End of explanation
class Message:
    def __init__(self,msg):
        self.msg = msg
    
    def __repr__(self):
        return('Message: %s' % self.msg)
x = Message('I have a secret')
x
Explanation: 由于IPython会获取__repr__方法返回的字符串（具体方法是 output = repr(obj)），并将其显示到控制台上。因此，我们可以为上面那个类添加一个简单的 repr 方法以得到一个更有意义的输出形式：
End of explanation
ipython profile create secret_project
#这会创建一个新的配置文件，目录在 ：~/.ipython/profile_secret_project/ipython_config.py
Explanation: 个性化和配置
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 配置。输入下面这样的命令即可新建一个新的个性化配置文件：
End of explanation
ipython --profile=secret_project
Explanation: 然后编辑新建的这个 profile_secret_project 中的配置文件，再用如下方式启动它：
End of explanation
<END_TASK>