Jupyter Notebook 入门指南

使用IPython

IPython简介

有时候仅需要通过几行 Python 代码来执行一些简单的功能,或测试某个库的基本使用方式。此时专门再编写一个脚本运行不免有些麻烦。好在 Python 提供了一个命令行的交互式控制台,可以立即执行输入的每一条语句并暂时保存变量。例如;

交互式控制台的特点在于其的交互功能,它可以直接查看变量的值,这样就避免了在简单的脚本中大量使用 print()

然而,Python 自带的交互式控制台功能过于薄弱。它没有语法高亮,没有自动补全,并且对缩进的处理也不够自然。如果代码较多,那么不但编写容易出错,而且难以阅读。

因此许多项目都尝试增强原有交互式控制台的功能。bpython 就是其中之一,bpython 在原有控制台的功能的基础上,提供了代码高亮、自动补全、括号匹配、缩进处理等功能,大大优化了交互体验。以下是 bpython 的简单交互效果:

bpython 可以通过命令行快速安装,但它目前只支持 Linux 系统。

IPython 则是一个更加强大的改进版交互式控制台,它不但支持代码高亮、自动补全等功能,还实现了跨平台以及更加丰富的扩展功能。以下是 IPython 的效果演示:

从截图中可以看到,IPython 还具有以下功能:

IPython 使用一个个单元格(cell)来对输入及输出编号,相比原先 Python 的提示符更加清晰。

单元格及其编号也为获取历史记录提供了一些便利。在 Python 的交互式控制台中都有一个特殊变量单下划线 _ ,它保存着上次访问的对象信息,而 IPython 则具有更多这样的特殊变量,例如:

  • _i4 用于获取 In[4] 单元的代码
In [6]: _i4 Out[6]: 'for i in range(2, 8):\n d.append(log(i))\n '
  • 两个下划线 __ 用于获取上上次访问的对象信息:
In [7]: __ Out[7]: [0.6931471805599453, 1.0986122886681098, 1.3862943611198906, 1.6094379124341003, 1.791759469228055, 1.9459101490553132]

这样的特殊变量还有很多。并且从返回的结果来看,IPython 还提供了更加美观的打印效果:列表、字典等会换行对齐展示,更易于阅读。IPython 也对其它常见的输出做了一定优化,使其更便于展示。

在 2 号单元格内,执行了以下命令:

In [2]: log?

这不是标准的 Python 语法,而是 IPython 的扩展语法,在某个函数或类后面添加一个问号可以显示其文档字符串。IPython 提供了更丰富的扩展语法,使得某些基础的功能可以通过简单的命令实现。再如,IPython 将一些简单的命令行功能整合进了扩展语法中:

In [1]: cd project/ E:\workspace\ai\project

IPython 通过 pip 就可以安装。接下来介绍 IPython 更多类似这样的扩展语法。

IPython的高级功能

提示与帮助

前文介绍了 IPython 可以在函数或类后面加上一个问号获取它的文档帮助。实际上,对于任意的对象都可以用此方法查看它的基本信息:

In [2]: l? Type: list String form: [1, 2, 3] Length: 3 Docstring: ...

除此之外,还可以通过两个问号 ?? 来获取函数的源代码:

In [3]: average?? Signature: average(a) Source: def average(a): """Returns the average of some numbers""" return sum(a) / len(a) File: e:\workspace\ai\project\<ipython-input-5-96774c320447> Type: function

当然,如果源代码不是使用 Python 编写的,那么就只能获取到一些基本信息了。

单个问号还可以配合通配符检查命名空间中所有匹配的成员:

In [16]: os.*dir? os.chdir os.curdir os.listdir ...

IPython 还提供了强大的自动补全功能。在访问模块或类的成员时,可以通过 TAB 键获取其包含的成员提示:

In [4]: import urllib.r request response robotparser

shell交互

IPython 还可以直接与命令行交互,使用 ! 符号作为前缀可以执行命令行命令:

In [5]: !echo ${PATH} /usr/local/sbin:...

注意,在 Windows 系统上默认调用的是 DOS 而不是 PowerShell 命令,即使 IPython 是通过 PowerShell 启动的。

该命令甚至还能作为一个值赋给变量:

In [6]: files = !ls In [7]: files Out[7]: ['user123', 'user01', 'user3', 'image']

这个结果有点类似列表,但它实际上是 IPython 提供的一种增强版列表,它提供了更多操作方法,例如使用函数或正则字符串筛选合适元素:

In [7]: files.grep(r'user\d+') Out[7]: ['user123', 'user01', 'user3']

也可以实现相反方向的交互,通过 {var} 将 Python 变量传入 shell :

In [8]: for i in range(1, 5): ....: !mkdir group{i}

魔法命令

IPython 中的一个更强大的功能是魔法命令(magic command),魔法命令可以用一种简洁的形式解决各种常见问题。

魔法命令以 % 符号作为前缀,如果要让魔法命令作用于整个单元,那么以两个 %% 作为前缀。魔法命令是一个很复杂的系统,接下来只介绍各种常用的魔法命令。

%run file 是一个很常用的魔法命令,它可以执行某一个 Python 脚本,在执行完后由 IPython 接管环境。这在 Debug 的时候很好用,当抛出异常时可以自动切换到 IPython 环境,此时可以使用 IPython 检查异常位置一些变量的值,或者查看异常的回溯栈等,在非图形界面下也可以很好地调试。

%timeit 也是一个很常用的魔法命令,用于分析一条或一块语句执行时长,这在科学计算或分析性能瓶颈的时候非常有用:

In [9]: a = np.arange(1, 1000) In [10]: %%timeit ...: b = np.empty_like(a) ...: for i, v in enumerate(a): ...: b[i] = math.log(v) ...: 517 µs ± 4.4 µs per loop (mean ± std. dev. of 7 runs, 1,000 loops each) In [11]: %timeit np.log(a) 9.63 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

直接从 Python 命令行控制台中复制的代码会带上提示符,如果要使用它还必须去除提示符。使用 %paste 命令可以从剪贴板中获取并执行代码,同时消除提示符的影响:

In [12]: %paste >>> from typing import NamedTuple >>> class User(NamedTuple): ... id_: int ... name: str ## -- End pasted text -- In [13]: u = User(id_=1, name='hello')

配合特殊变量 In 可以获取去除提示符的实际执行的代码:

In [14]: print(In[13]) from typing import NamedTuple class User(NamedTuple): id_: int name: str

这里对魔法命令暂时就介绍这么多。可以通过 %magic 打开魔法命令的帮助文档,所有魔法命令可以通过 %lsmagic 获取,通过使用 ? 符号就可以了解每个魔法命令的使用。

使用Jupyter notebook

简介与安装

IPython 的功能非常丰富,甚至超越了原生 Python 的功能。然而 IPython 毕竟只是个命令行的控制台,进一步提升的空间被限制了。

基于此,IPython 发展出了一种更强大的编辑器模式:Jupyter Notebook 。Notebook 具有可视化的编辑界面,并使用文件来编辑与保存单元格的内容。

以下是 Jupyter Notebook 的使用截图:

Jupyter 在保留 IPython 特点的同时,功能与交互性都更加强大。

Jupyter 的安装十分简单,只需要通过 pip 安装即可:

$ pip install jupyter

注:目前主流的 Jupyter 安装和管理都是通过 Anaconda 完成的,这里使用命令行仅仅是为了简化使用与配置。关于 Anaconda 的使用网络上已经有较多文章,这里不再重复。

然后在命令行中就可以启动 Notebook :

$ jupyter notebook

这会在浏览器中打开一个新的页面,稍等片刻后便会进入 Notebook 的初始界面:

认识Notebook

Jupyter Notebook 也是基于文件执行的,其文件后缀为 .ipynb ,它实质上是一个 Json 文件,只有使用 Jupyter 等支持的编辑器打开才能正常被渲染。在 Jupyter 提供的浏览器页面中,可以像别的编辑器一样新建、修改和保存这种文件,还可以将其导出为 Python 代码、Markdown 文本、PDF 文档等。

进入 Jupyter 后,它提供了 3 个选项卡:

  1. Files 页用于管理工作路径下的文件
  2. Running 页显示当前正在运行的终端和 Notebooks
  3. Clusters 页用于处理计算群集

新建或打开一个 Notebook 文件后,即可像 IPython 一样在各个单元格内编写、执行代码:

但与 IPython 不同的是,Notebook 单元格的代码可以修改后重新执行,这会使得虽然上面某个单元格的代码修改了,但是下面单元格的输出结果还没更新,并且原始的数据也会被覆盖。注意单元格左侧 In 中的编号才表示真正的执行顺序。

Jupyter 提供的菜单中有各种功能,例如新建或保存文件、合并或移动单元格、控制显示内容等,它们使用较为简单,这里就不展开介绍了。

Notebook 中的单元格除了可以编写代码,还可以使用其余类型的单元格,例如通过 Markdown 单元格编写简单文档并嵌入 LaTeX 公式,或者使用 Raw 单元格显示纯文本。一些 Notebook 的扩展还允许它编写 bash 脚本、执行 R 语言甚至 SQL 命令等。

Notebook 的单元格在编写代码时,具有以下两种模式:

  • 编辑模式:此时单元格外围的边框颜色为绿色,可以直接在该单元格中输入代码或文本
  • 命令模式:此时单元格外围的边框颜色为蓝色,键盘操作将作为命令执行

点击单元格代码外区域或使用快捷键 Esc 即可进入命令模式,此时可以使用以下常用的命令对单元格做调整:

命令 功能 命令 功能
L 在单元格中显示或取消显示代码行号 X 剪切选中的单元格
M 将该单元格变为 Markdown 类型 C 复制选中的单元格
Y 将该单元格变为 Code 类型 V 将单元格粘贴到当前单元格下方
A 在当前单元格上方插入一个 Code 单元格 Shift+↑Shift+↓ 向上或向下连续选择多个单元格

返回编辑模式可以点击代码区域或使用快捷键 Enter 。运行代码可以使用如下快捷键,它们在任意模式下都可以直接使用:

  • Ctrl+Enter :运行选中单元格
  • Shift+Enter :运行选中的单元格,并选中下一个单元格
  • Alt+Enter :运行选中的单元格,并在下方插入一个新的单元格

配置Jupyter

Jupyter 的某些配置可以修改以满足使用要求。

在启动时可以通过命令行参数临时修改配置。例如 Jupyter 运行的默认端口号是 8888 ,可以通过如下参数修改端口号:

$ jupyter notebook --NotebookApp.port=8088

如果需要永久更改某个配置,那么就需要使用配置文件。初次使用需要通过如下命令生成配置文件:

$ jupyter notebook --generate-config

然后可以根据提示信息找到配置文件的位置。该文件是一个纯 Python 文件,使用变量保存所有的配置信息,并且默认情况下配置都被注释了。

如果要启用某项配置只需要取消注释即可,这些配置的说明都在注释中写的很明白了。例如,假设要更改 Jupyter 打开后的根目录,那么可以修改以下配置:

## The directory to use for notebooks and kernels.
#  Default: ''
c.NotebookApp.notebook_dir = r'E\workspace'

管理内核

Notebook 在浏览器前端编写代码后,由内核(kernel)负责执行并返回结果。内核保存着单元格中的所有变量,因此一个 Notebook 所有的代码都在一个内核中执行。

在编辑界面中,可以在 kernel 菜单中终止或重启内核。但需要注意的是:内核一旦中断,所有的变量都会丢失,只有重新执行才可以访问这些变量。

在使用 Python 的过程中,免不了要管理各种虚拟环境,此时就需要管理 Jupyter 的各种内核。内核管理需要借助 ipykernel 第三方库实现,不过它应该在安装 Jupyter 时已经作为一个依赖被一并安装了。

使用以下命令即可查看当前 Jupyter 具有的全部内核:

$ jupyter kernelspec list

每个内核都是一个目录,它主要包含以下文件:

kernel.json
logo-32x32.png
logo-64x64.png
logo-svg.svg

通过在 kernels 目录中创建多个类似这样的目录并修改 kernel.json 文件的内容,即可创建多个使用不同解释器的内核。kernel.json 文件中的内容为:

{
    "argv": [
        "E:\\workspace\\ai\\env\\sci\\Scripts\\python.exe",
        "-m",
        "ipykernel_launcher",
        "-f",
        "{connection_file}"
    ],
    "display_name": "Python 3 (sci)",
    "language": "python",
    "metadata": {
        "debugger": true
    }
}

这里主要修改 "argv"[0] 决定的解释器路径和 "display_name" 决定的内核名,启动 Jupyter 后就能在 Kernel 菜单中更换内核并使用不同的虚拟环境了:

高级交互效果

借助浏览器的前端技术,Jupyter 可以使用在命令行甚至一般的编辑器中无法实现的交互效果。

在之前介绍 Jupyter 时就展示了在单元格内显示,借助 IPython.display 模块的各种显示类,可以在浏览器中显示各种格式的文本、数学公式乃至多媒体文件等:

还可以使用控件(widget)实现更强大的交互效果。控件的实现由第三方库 ipywidgets 提供,它应该在安装 Jupyter 时就被一并安装了,如果没有的话也可以使用 pip 安装它。

先来看一个最简单的示例,在输出中显示一个滑块:

w = ipywidgets.IntSlider()
w

交互最主要的就是处理各种事件,这可以通过向 .observe() 方法提供回调函数实现。每次发生交互时,事件的相关信息将以字典的形式由回调函数处理:

w = ipywidgets.IntSlider()
w.observe(lambda e: print(e['new']), names=['value'])
w

由于许多动作都会导致事件的发生,因此这里通过 names 参数限制处理的事件,即只有选定的值发生变化时才处理该事件。滑块在滑动过程中会不断触发事件,在复杂操作时可能引起卡顿。如果想让滑块在最终释放时才执行动作,那么可以在初始化时将 continuous_update 参数设置为 False

按钮之类的特殊控件没有那么多交互逻辑,可以使用其它方法简化处理,例如:

w = ipywidgets.Button(description='click me')
w.on_click(lambda w: print(f'clicked {w}'))
w

给多个控件建立联系也是很常见的做法,这点可以通过 link() 函数实现。例如,以下在一个滑块和进度条之间建立联系,使滑块的位置被同步反映到进度条上:

w1 = ipywidgets.FloatSlider()
w2 = ipywidgets.FloatProgress()
ipywidgets.link((w1, 'value'), (w2, 'value'))

display.display(w1, w2)

如果要建立单向联系,可以使用 dlink() 。这种联系的后台交互由内核实现,因此内核断开后就无法继续使用。如果要使用纯前端方法实现的联系,可以使用 jslink()jsdlink()

一种更为强大的交互效果由 interact() 函数实现。该函数可以根据初始值自动选择合适的控件展示,以下简单展示了几个示例:

ipywidgets 的内容非常复杂,它不仅包含了大量常用的输入框、按钮、框架盒系列的控件,还允许对控件的样式做详细的定制,这里就不展开说明了。要了解更多有关它的内容,可以参考官方文档

JupyterLab:更强大的Notebook IDE

Jupyter 作为 Notebook 的开发环境,只提供了基本的界面及一些简单的单元格编辑与处理功能。JupyterLab 则是一个更高级的浏览器 Notebook 开发环境,它提供了更加丰富的功能,其使用截图如下:

用过 VS Code 等编辑器的话应该会对该界面比较熟悉,JupyterLab 提供了更实用的文件管理、预览、分屏、状态显示等功能,并且还可以通过安装扩展进一步丰富其功能。

JupyterLab 可以通过 pip 快速安装:

$ pip install jupyterlab

然后就可以在命令行中运行:

$ jupyter lab

Jupyter 及 Notebook 的发展远没有结束,除了以上介绍的技术外,Jupyter Hub 可以用于多人协同开发,而各个常用 Python IDE(如 Pycharm 和 VS Code )也推出了内置的 Notebook 开发环境,使 Notebook 可以使用它们提供的代码补全、语法检查、调试、环境管理等更多功能。

京ICP备2021034974号
contact me by hello@frozencandles.fun