阅读 667

使用自动加载来加速IPython和Jupyter的工作

我尝试用Jupyter笔记本或IPython会话来完成我所有的交互式Python开发。我喜欢这些环境的主要原因之一是%autoreload神奇。%autoreload 有什么特别之处,为什么它经常使开发更快、更简单?

为什么是IPython和Jupyter?

在进一步讨论之前,如果你还没有使用过IPython和Jupyter,请看看ipython互动教程。它很好地解释了为什么使用IPython比默认的Python解释器要好。它有很多有用的功能,但在本文中,我将只讨论一个功能(魔法),特别是其中的一个魔法(%autoreload )。Jupyter笔记本,像IPython一样,支持大多数相同的魔法,所以本教程的大部分内容在交互式IPython会话或Jupyter笔记本会话中都可以使用。需要注意的一点是,我在这里说的是Python,而不是在Jupyter笔记本中运行的其他语言。

什么是魔法?

魔术就是你可以在IPython或Jupyter会话中调用的特殊函数。它们有两种形式:行和单元。一个行魔法的前缀是一个% ,一个单元魔法的前缀是两个,%% 。一个行魔法消耗一行,而一个单元魔法消耗魔法下面的行,允许更多的输入。在这篇文章中,我们将只看其中一个行魔法,即%autoreload 魔法。

为什么要自动加载?

%autoreload 魔法改变了Python会话,使模块在进入执行在IPython提示符(或Jupyter笔记本单元)上输入的代码之前,在该会话中自动重新加载。这意味着加载到你的会话中的模块可以被修改(在你的会话之外),而这些修改将被检测到并重新加载,而你不必重新启动你的会话。

这可能是非常有用的。让我描述一个典型的场景。假设你有一个你已经创建并正在增强的Jupyter笔记本,而你需要从几个来源获得数据。你通过执行你在会议开始时导入的模块中的函数来获得数据,这些模块是你控制的Python代码。对于许多用户来说,这将是一个非常典型的用例。此外,假设在你的笔记本中,你把所有的数据加载到内存中,这需要整整5分钟。然后你开始处理这些数据,并很快意识到你需要从你控制的某个模块的某个函数中获得稍微不同的数据,所以你需要添加另一个参数来查询不同的数据。你如何

  1. 做这个改变
  2. 测试这个变化
  3. 继续你的工作

在大多数情况下,你会在编辑器或IDE中打开底层代码,对其进行修改,在另一个会话中进行测试(或使用单元测试),然后可选择在本地安装更改。但是,已经有一些数据已经加载的笔记本怎么办?继续工作的一个方法是重启你的Jupyter内核,以接收你刚刚做的修改,将所有数据重新加载到内存中(至少需要5分钟),然后继续你的工作。

但是有一个更好的方法,使用autoreload 。在你的Jupyter会话中,你首先加载autoreload 扩展,使用%load_ext 魔法。

%load_ext autoreload
复制代码

现在,%autoreload 魔法在你的会话中是可用的。它可以接受一个单一的参数,指定模块的autoreloading将如何进行。该扩展还提供了另一个魔法,%aimport ,它允许精细地控制哪些模块受到自动加载的影响。如果没有给%autoreload ,那么它将立即重新加载所有模块(除了那些被%aimport 排除的模块,如下图所示)。你可以运行它一次,然后使用你更新的代码。

autoreload 的可选参数有三个有效值。

  • 0 - 禁用自动重载
  • 1 - 在执行已经输入的Python代码之前,每次都会重新加载由%aimport 导入的所有模块
  • 2 - 在执行已经输入的Python代码之前,每次都要重新加载所有模块(除了那些被%aimport 排除的模块)

为了调节受autoreload 影响的模块,使用%aimport 法宝。它的工作方式如下。

  • 无参数 - 列出将被导入或不被导入的模块
  • 有一个参数--提供的模块将被导入。%autoreload 1
  • 用逗号分隔参数 - 列表中的所有模块都将被导入。%autoreload 1
  • 参数前有-- 该模块不会被自动加载。

对我来说,我使用%autoreload 最常见的方式是在我的初始开发工作中,当我有可能改变 Python 模块和笔记本代码时,只包含所有的东西(即运行%autoreload 2 ),而在其他情况下,根本不使用它。但是,拥有控制权是很有用的,特别是当你要加载很多模块的时候。

例子

对于一个具体的例子,你可以用它来进行学习,制作两个Python文件,auto.pyauto2.py ,并将它们保存在Jupyter笔记本上,并在下面输入。每个 Python 文件中都应该有一个简单的函数,如下所示。

# in auto.py
def my_api(model, year):
    # dummy result
    return { 'model': model, 'year': year, }

# in auto2.py
def my_api2(model, year):
    # dummy result
    return { 'model': model, 'year': year, }
复制代码

现在,让我们导入这两个模块,并使用IPython/Jupyter帮助检查API方法,在函数上附加一个? 。你应该看到,导入的模块与你在Python文件中的代码相匹配。

import auto
import auto2

auto.my_api?
复制代码
Signature: auto.my_api(model, year)
Docstring: <no docstring>
File:      ~/projects/python_blogposts/tools/auto.py
Type:      function
复制代码

现在,在一个单独的编辑器中,为auto.my_api 函数添加第三个参数(也许让它接受第三个color 参数)。保存该文件。我们看到它了吗?刷新帮助单元来看看。

不,还没有。让我们打开自动加载。

%autoreload 2
复制代码

现在,当我检查auto.my_api ,我看到了新的参数。它成功了!

现在我可以修改设置,以便只重新加载auto2 模块,而不是auto 。但首先,让我们看看要重新加载和跳过的模块。默认情况下,它包括所有的模块,一个也不跳过(因为我用2 作为初始参数)。

%aimport
Modules to reload:


Modules to skip:
复制代码

让我们关闭auto

%aimport -auto
%aimport
Modules to reload:


Modules to skip:
auto
复制代码

现在,如果我修改了auto 中的代码,我不应该在这个会话中看到这些变化。使用%aimport ,你可以限制哪些代码被重新加载。

注意事项

值得注意的是,模块重载并不完美。你不应该在生产代码中使用这个功能,它将会减慢速度。另外,如果你正在实时编辑你的代码,并让它处于断裂状态,最近成功加载的代码将是在你的会话中运行的代码,所以它可能会让你感到困惑。这可能不是你想要的修改大量代码的方式,但在进行增量修改时,它可以很好地工作。

为了观察被破坏的代码会是什么样子,打开正在被自动加载的模块(auto2.py),添加一个语法错误(例如,也许在某个地方放上不匹配的帕累斯)并保存文件,然后在笔记本单元中执行该模块的函数。你应该看到autoreload 报告单元格中的语法错误的跟踪。你只会看到这个错误一次,如果你重新执行单元格,它不会显示同样的错误,但会使用最后加载的代码版本。

另外,请注意,有一些事情并不总是奏效,比如从模块中删除函数,将类中的@属性改为普通方法,或者重新加载C扩展。在这些情况下,你将需要重新启动你的会话。你可以在文档中看到更多细节。

总结

如果你以前没有使用过%autoreload ,那么当你有一个IPython或Jupyter会话,里面有很多数据,想对本地模块做一个小改动时,可以试试。希望它能为你节省一些时间。

你可能想看看 这篇文章 ,看看如何使用其他魔法来查看Jupyter或IPython会话中的变量。

The postUsing autoreload to speed up IPython and Jupyter workappeared first onwrighters.io.

文章分类
开发工具
文章标签