使用python3从位于另一个目录中的模块导入本地函数,并在jupyter笔记本中使用相对导入

2024-04-24 19:42:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个类似于下面的目录结构

meta_project
    project1
        __init__.py
        lib
            module.py
            __init__.py
    notebook_folder
        notebook.jpynb

notebook.jpynb中工作时,如果尝试使用相对导入访问module.py中的函数function(),则使用:

from ..project1.lib.module import function

我得到以下错误

SystemError                               Traceback (most recent call last)
<ipython-input-7-6393744d93ab> in <module>()
----> 1 from ..project1.lib.module import function

SystemError: Parent module '' not loaded, cannot perform relative import

有什么方法可以使用相对导入来实现这一点吗?

注意,笔记本服务器是在meta_project目录级别实例化的,因此它应该可以访问这些文件中的信息。

另外,请注意,至少最初的目的project1没有被认为是一个模块,因此没有__init__.py文件,它只是一个文件系统目录。如果问题的解决方案需要将其视为一个模块,并包含一个__init__.py文件(甚至是一个空白文件),那就可以了,但这样做还不足以解决问题。

我在机器和相对导入之间共享此目录允许我在任何地方使用相同的代码,&;我经常使用笔记本进行快速原型设计,因此,涉及到将绝对路径组合在一起的建议不太可能有帮助。


Edit:这与Relative imports in Python 3不同,后者通常讨论Python 3中的相对导入,特别是从包目录中运行脚本。这与jupyter笔记本中的工作有关,该笔记本试图调用另一个目录中的本地模块中的函数,该目录具有不同的常规和特定方面。


Tags: 模块文件pyimport目录projectinitlib
3条回答

我在this notebook中有一个几乎和你一样的例子,我想用干巴巴的方式来说明相邻模块函数的用法。

我的解决方案是通过在笔记本中添加类似这样的代码片段来告诉Python额外的模块导入路径:

import os
import sys
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
    sys.path.append(module_path)

这允许您从模块层次结构导入所需的函数:

from project1.lib.module import function
# use the function normally
function(...)

注意,如果您还没有空的__init__.py文件,则必须将其添加到project1/lib/文件夹中。

来到这里是为了寻找在笔记本电脑中工作时将代码抽象到子模块的最佳实践。我不确定是否有最佳实践。我一直在提议这个。

这样的项目层次结构:

├── ipynb
│   ├── 20170609-Examine_Database_Requirements.ipynb
│   └── 20170609-Initial_Database_Connection.ipynb
└── lib
    ├── __init__.py
    └── postgres.py

20170609-Initial_Database_Connection.ipynb

    In [1]: cd ..

    In [2]: from lib.postgres import database_connection

这是因为默认情况下,Jupyter笔记本可以解析cd命令。注意,这并没有利用Python笔记本的魔力。它只不过是在不加%bash前缀的情况下工作。

考虑到我在Docker中使用Project Jupyter Docker images中的一个工作的100次中有99次,下面的修改等幂的

    In [1]: cd /home/jovyan

    In [2]: from lib.postgres import database_connection

到目前为止,公认的答案对我最有效。不过,我一直担心的是,有一种可能的情况是,我可能会将notebooks目录重构为子目录,需要更改每个笔记本中的module_path。我决定在每个笔记本目录中添加一个python文件来导入所需的模块。

因此,具有以下项目结构:

project
|__notebooks
   |__explore
      |__ notebook1.ipynb
      |__ notebook2.ipynb
      |__ project_path.py
   |__ explain
       |__notebook1.ipynb
       |__project_path.py
|__lib
   |__ __init__.py
   |__ module.py

我在每个笔记本子目录中添加了文件project_path.pynotebooks/explorenotebooks/explain)。此文件包含相对导入(从@metakermit)的代码:

import sys
import os

module_path = os.path.abspath(os.path.join(os.pardir, os.pardir))
if module_path not in sys.path:
    sys.path.append(module_path)

这样,我只需要在project_path.py文件中进行相对导入,而不是在笔记本中。然后,笔记本文件只需要在导入project_path之前导入lib。例如在0.0-notebook.ipynb中:

import project_path
import lib

这里的警告是,逆转进口是行不通的。这不起作用:

import lib
import project_path

因此,进口时必须小心。

相关问题 更多 >