【问题标题】:How to use code from external Python files in Jupyter notebook?如何在 Jupyter 笔记本中使用来自外部 Python 文件的代码?
【发布时间】:2019-10-22 04:22:30
【问题描述】:

我有一个作为 Jupyter 笔记本开始的宠物项目。至此,我把所有的 Python 代码都放在了 notebook 里。

一开始一切都很好。但随着时间的推移,我在笔记本上写的代码变得越来越复杂。现在它几乎无法管理:当我发现错误时,我需要

  1. 导航到有错误的代码部分(通常在笔记本的开头),
  2. 修复那里的错误,
  3. (通常)转到笔记本底部以触发执行我更改的代码。

我想把代码分成两部分:

  1. 将存储为 Python 文件,我将使用编辑器(和/或 IDE)对其进行编辑。
  2. Jupyter 笔记本中调用代码部分 1 并显示其输出的代码(即,使用 Jupyter 笔记本作为第 1 步中 Python 代码的用户界面)。

假设笔记本在我的本地机器上运行(Windows 7;Jupyter 在 Anaconda 中运行)并且 Python 文件也存储在本地。

有哪些好方法可以使用 IPython 文件中的代码,以便我可以频繁且快速地修改此代码?

我所说的“频繁且快速”是指“将更改从 Python 文件传播到笔记本所需的步骤尽可能少”。理想的解决方案是我更改其中一个 Python 文件,运行一个命令,然后在 Jupyter 笔记本中提供更改。或者,用一个更老的比喻,我希望它像 PHP 一样——您经常更改代码并立即看到更改的结果。

更新 1:我尝试在单元格中使用带有%load TestClass.py 的解决方案。

问题在于,如果文件更改,单元格内容不会更新。

例子:

假设我放了文字

class TestClass:
    def __init__(self):
        print("TestClass constructor")

进入TestClass.py。然后我在 Jupyter notebook 中使用%load TestClass.py 创建一个单元格。当我执行该单元格时,来自TestClass.py 的代码被导入,%load TestClass.py 行被注释掉。

现在我把TestClass.py改成

class TestClass:
    def __init__(self):
        print("TestClass constructor")
        print("change")

当我执行单元格时,它的内容并没有改变。

【问题讨论】:

  • 这可以通过具有主要.py 文件的魔法单元来实现,然后使用%load 导入文件,如本文stackoverflow.com/questions/21034373/… 中所述,或者使用%%writefile myfile.py 写入所有将笔记本的单元格转换为可用于调试的 python 文件?
  • @Alessi42 谢谢。此解决方案不起作用,因为当文件更改时,更改不会传播到 IPython(请参阅更新 1)。
  • 如果你只是编写一个带有方法的类并将它们导入到 main.ipynb 中会发生什么?示例:假设您想要为所有可视化创建一个类,然后创建一个可视化.py。然后在 main.ipynb 包装器中使用它。只需致电:import visualization as vis vis.visualize_barchart(X) 并同时管理两者,您可以使用 Pycharm IDE 可能是
  • @coldy main.ipynb 应该写什么?

标签: python jupyter-notebook jupyter


【解决方案1】:

我通常卸载要刷新的模块然后重新导入。绑定到旧代码的对象不会被刷新,我时不时地必须重新启动内核,但这比每次重新启动内核要快得多。我只建议那些已经了解或愿意了解从 sys.modules 中删除模块的影响的人。但它为我节省了很多时间。

请参阅 UnloadModules here

我在 Jupyter 中的典型用法:

from coppertop import Unload
Unload("fred.joe")
from fred.joe.sally import arthur
arthur.doSomethingInteresting()

【讨论】:

    【解决方案2】:

    你在写:

    并且 %load TestClass.py 行被注释掉了。

    我明白,您将其注释掉。为什么?重新运行导入并更新类。

    BTW !run TestClass.py 应该做同样的事情 - 至少在 Jupyter NB 中。

    【讨论】:

    • Re 你把它注释掉:我没有。第一次运行单元格后自动注释掉。
    • 你说得对——我不知道“%load”的行为。所以我对“%run”做了同样的事情,单元格没有被注释掉。因此,对于您未来的工作,这就是要使用的命令。将它放在笔记本的开头以及您希望重新加载的任何方便的地方。请记住,依赖于导入的命令不会自动更新(例如类的实例等)。所以要么你把notebook从头重新运行到当前位置,要么把相关代码放在一个函数中,可以从NB的任何地方触发。
    【解决方案3】:

    听起来像 IPython 的 autoload extension 正是您所需要的。只需插入

    %load_ext autoreload
    %autoreload 2
    

    在 Jupyter notebook 的第一个单元格中,导入的 python 模块会在更改时自动重新加载。你也可以对已安装的 python 包进行更改,前提是你已经安装了它们editable

    【讨论】:

      【解决方案4】:

      我一直在研究类似的问题。如果您使用 Jupyterlab 而不是较旧的 Jupyter Notebooks,您可以同时打开多个 nb,编辑保存您的函数的一个,然后在导入时重新启动另一个内核以更新。不幸的是,您丢失了所有变量,需要再次运行整个笔记本,但它允许第一个 nb 中的更改传播到第二个。

      这不是一个完美的答案,但让我可以继续从事我的项目。

      【讨论】:

      • 谢谢,但不幸的是 JupyterLab 不能在我的机器上运行。
      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 2016-07-24
      • 1970-01-01
      • 2020-11-16
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      相关资源
      最近更新 更多