【问题标题】:Import py file in another directory in Jupyter notebook在 Jupyter notebook 的另一个目录中导入 py 文件
【发布时间】:2018-08-22 04:23:17
【问题描述】:

我的问题与this 有关。我在 Jupyter Notebook 中使用 Python 3.6。我的项目目录是/user/project。在这个目录中,我构建了许多模型,每个模型都有自己的文件夹。但是,有一个常见的 functions.py 文件,其中包含我想在所有模型中使用的功能。所以我想将functions.py 文件保留在/user/project 中,但可以从/user/project/model1/user/project/model2 等中的.ipynb 文件中调用它……我该怎么做?

【问题讨论】:

  • 您链接的问题中的解决方案对您不起作用吗?你收到什么错误?这有什么帮助吗:stackoverflow.com/q/42163470/8146556
  • Python 模块/包/导入管理是如此灵活的集群,所以这些问题总是有帮助的:-)

标签: python-3.x python-import


【解决方案1】:

没有简单的方法可以将 python 文件导入另一个目录。 这与 jupyter notebook 无关

这里有 3 个解决您问题的方法

  1. 您可以将包含要导入的文件的目录添加到您的路径中,然后像这样导入文件:
import sys  
sys.path.insert(0, '/path/to/application/app/folder')

import file
  1. 您可以通过在要导入的文件夹中有一个空的__init__.py 文件来创建本地模块。关于文件夹层次结构,有一些weird rules 必须考虑在内。

  2. 您可以为要导入的文件创建一个模块并全局安装它。

【讨论】:

【解决方案2】:

我一直在考虑这个问题,因为我不喜欢 sys.path.append() 的答案。我提出的一个解决方案是使用内置的 Jupyter 魔术命令来更改当前工作目录。假设你有这个文件结构:

project
├── model1
|   └── notebook1.ipynb
├── model2
|   └── notebook2.ipynb
└── functions.py

无论您是想从notebook1.ipynbnotebook2.ipynb 导入functions,您都可以简单地在包含您的包导入的单元格之前添加一个包含以下行的单元格:

%cd ..

这会将当前工作目录更改为笔记本的父目录,然后将函数模块的路径添加到 Python 将检查包的默认位置。导入functions

import functions

如果您在要导入的同一包目录中有多个模块,这将类似地工作:

project
├── model1
|   └── notebook1.ipynb
├── model2
|   └── notebook2.ipynb
└── package
    ├── functions1.py
    └── functions2.py 

您可以像这样从package 导入两个模块functions1functions2

from package import functions1, functions2

编辑:正如下面所指出的,如果包含魔法命令的单元多次运行,本地导入将不再起作用(当前工作目录将在每次重新运行命令时更改为上面的目录)。为防止这种情况发生,%cd .. 命令应位于笔记本顶部的自己的单元格中(与导入不同的单元格中)和导入之前之前,因此它不会运行多次。重新启动内核并运行所有单元将重置当前工作目录,但仍将返回所需的导入/结果。

【讨论】:

  • 这不是一个好的解决方案。 %cd .. 每次运行单元格时都会为您提供不同的结果(将工作目录更上一层楼)
  • @danwild 包含此内容的单元格是否需要多次运行?也许它与您的工作流程不兼容,但我可以在笔记本顶部运行一次,而不必再担心它——如果我需要重新运行单元,重新启动内核并运行所有单元每次都会给出相同的结果时间(将工作目录上移一个)
  • 如果需要重启内核来重新运行笔记本不是代码异味,我不知道是什么。笔记本的其他用户如何知道他们需要这样做?他们只看到以前没有的导入错误。
  • 如果魔法命令在它自己的单元格中并且用户没有重新启动整个笔记本,为什么还要重新运行那个单元格(假设这个魔法命令是单元格中唯一的东西)?也许这种方法不适用于每个人的工作流程,但它对我有帮助,我希望我能早点找到这样的简单解决方案。
【解决方案3】:

发现自己的处境与 OP 完全相同,要创建几个笔记本,因此希望将它们组织在不同的子文件夹中

试过这个似乎可以满足我的需要并且对我来说似乎更干净

import os
os.chdir(os.path.dirname(os.path.dirname(os.getcwd())))

我的函数在上面两层,所以嵌套了两个os.path.dirname(不同的文件夹结构可能只有一个或多个)

刚刚实现它并且工作正常,顺便说一句,我正在使用 JupyterLab 启动...在函数所在的位置上方两个级别

【讨论】:

  • 好吧,我只是偶然发现了一个不这样做的好理由,即重新运行单元格。可以避免使用 if os.getcwd().split('\\').pop() == 'definitions': os.chdir(os.path.dirname(os.path.dirname(os.getcwd()))) 代替(“定义”是我的子文件夹的名称)
【解决方案4】:

除了来自 adhg 的回答,我建议使用 Pathlib,以实现 Linux/Windows/WSL 路径格式之间的兼容性:

假设如下文件夹结构:

.
├── work
|   ├── notebook.ipynb
|   └── my_python_file.py
├── py
|   ├──modules
|   |    ├──__init__.py # empty
|   |    └──preparations.py
|   ├──__init__.py # empty
|   └── tools.py
├──.git
└── README.md

my_python_file.py(或笔记本notebook.ipynb)中加载tools.pypreparations.py

import sys
from pathlib import Path

# in jupyter (lab / notebook), based on notebook path
module_path = str(Path.cwd().parents[0] / "py")
# in standard python
module_path = str(Path.cwd(__file__).parents[0] / "py")

if module_path not in sys.path:
    sys.path.append(module_path)

from modules import preparations
import tools
...

【讨论】:

    【解决方案5】:

    我过去通过在 Jupyter 笔记本所在的目录中创建一个指向它要加载的库的符号链接来解决这个问题,以便 python 表现 em> 好像模块在正确的路径中。因此,对于上面的示例,您将在 Jupyter 单元中运行以下命令每个目录一次

    !ln -s /user/project/functions.py functions.py
    

    然后你可以导入

    import functions
    

    注意:我只在 Linux 和 Mac Os 上试过这个,所以我不能保证 Windows。

    【讨论】:

      【解决方案6】:

      假设您有一个名为 Jupyter 的文件夹,并且您希望从另一个名为 nn_webserver 的文件夹中导入模块(员工)。

      可视化它:

      这样做:

      import sys
      import os
      
      module_path = os.path.abspath(os.path.join('..'))
      if module_path not in sys.path:
          sys.path.append(module_path+"\\nn_webserver")
      
      from employee import motivation_to_work
      

      查看来自@metakermit 的更多信息here

      【讨论】:

      • 我更喜欢这个相对路径而不是另一个答案,它使用绝对路径。即使您将整个项目安装在不同的系统上,相对路径也将保持有效,而绝对路径则需要调整。
      【解决方案7】:

      我建议将functions.py 作为一个包安装在您的虚拟环境中。这样做有一些好处:

      1. 您可以从位于任何位置但在给定环境(内核)中的任何 iPython 笔记本访问 functions.py 文件。
      2. 一旦你改变了functions.py文件中的任何函数,你就不需要一次又一次地重新加载你的iPython notebook。它将自动重新加载每个更改。

      这是可以做到的方式:

      • 在您的项目文件夹中创建setup.py 文件 (https://docs.python.org/2/distutils/setupscript.html)
      • 激活您的虚拟环境,转到您的项目位置,然后使用此命令pip install -e .
      • 然后,在你的 iPython 笔记本中:

        %load_ext 自动重载

        %autoreload 1

        %aimport yourproject.functions

        从函数导入 *

      就是这样!

      【讨论】:

      • 您将如何使用此设置分享您的工作?我的意思是,如果同事需要复制您的环境,最佳做法是什么?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-07
      • 2020-02-29
      • 1970-01-01
      • 1970-01-01
      • 2020-03-20
      • 2022-07-16
      • 2014-05-22
      相关资源
      最近更新 更多