Python相对路径导入:从另一个项目目录导入包

时间:2020-07-02 21:35:50

标签: python jupyter-notebook

我知道这个主题有很多问题,但是没有一个问题对我有很大帮助。

我有一个python项目目录,即git_project(git存储库)。我想要创建一个名为notebooks的单独目录,在该目录中,我将使用git_project保存所有笔记本以进行分析。我不想将笔记本放在git_project的根目录下。我已经将git_projectnotebooks目录都保留在保存我所有项目的常规目录中。我有以下结构:

my_projects
│ 
├── notebooks
│   └── notebook.ipynb
└── git_project
    └── config
        └── cfg.json
    └── source
        └── config.py

config.py的内容:

import json
def get_cfg():
     with open('config/cfg.json', 'r') as f:
         cfg = json.load(f)
     return cfg

notebook.ipynb的内容:

import sys
import os

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

from git_project.source.config import get_cfg
get_cfg()

现在,当我在notebook.ipynb中运行代码时,出现以下错误:

---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-7-6796ee7f0100> in <module>
----> 1 get_cfg()

~/Documents/my_projects/git_project/source/config.py in get_cfg()
      1 def get_cfg():
----> 2     with open('config/cfg.json', 'r') as f:
      3         cfg = json.load(f)
      4     return cfg

FileNotFoundError: [Errno 2] No such file or directory: 'config/cfg.json'

但是,如果我将notebook.ipynb文件移动到git_project的根目录。然后我没有得到这个错误。这只是一个例子。我在git_project的其他模块中有很多类似的问题,而git_project包含已经在生产环境中运行的代码。因此,在这里更改git_project中的任何内容都不可行。 但是正如我所说,我不想将笔记本移动到git_project内,而是希望将它们放在并行目录中以进行分析。如果需要,我可以提供更多信息。

我正在使用Python 3.6+,它甚至不需要再放置 init .py文件来制作目录包。

我应该怎么做才能使其正常工作?任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

问题是当您调用open('config/cfg.json', 'r')时,它打开的路径是相对于python代码启动目录的。在这种情况下,它是您的my_projects/notebook目录。您可以通过在get_cfg()内的config.py中添加以下打印品来看到这一点:

print(os.getcwd())  # this prints out the current working directory
print(__file__)     # this prints out the path of this script

如艾哈迈德(Ahmet)所建议的那样,修改../git_project/config/cfg.json的路径是可以的,但是您的python实现将与笔记本文件夹的位置绑定在一起。如果决定重组笔记本文件夹,它将再次损坏。 一种可能的方法是解析脚本路径:__file__

import json
import os
def get_cfg():
    script_dirname = os.path.dirname(__file__)
    config_path = os.path.join(script_dirname, '..', 'config', 'cfg.json')
    with open(config_path, 'r') as f:
        cfg = json.load(f)
    return cfg

相似的建议:(Reading file using relative path in python project)。这也是python-packaging docs中建议的方法:

已安装的库要使用的文件(例如数据文件) 以支持特定的计算方法)通常应放在 在Python模块目录本身中。 ... 这样,加载这些文件的代码可以轻松指定相对 使用者模块的__file__变量的路径。

如果您不想触摸git_project中的当前文件,则可以在python笔记本中运行更改目录命令以指向正确的位置:

In [1]: %cd ../git_project

每次重新启动笔记本内核时,都需要调用该行一次。您也可以在笔记本中验证当前工作目录:

In [2]: %ls

答案 1 :(得分:0)

作为评论中讨论的后续内容...

即使采用相对路径的方法行得通,通常还是最好使用更具可扩展性的方法-将环境变量与项目根目录一起使用。

在这种情况下,您的笔记本电脑真正独立于项目,并且可以根据需要使用任意数量的笔记本电脑。 这是有关如何在Jupiter中使用ENV变量的绝佳explanation。 我更喜欢使用dotenv方法。 在您的笔记本文件夹中创建.env。在您的项目路径中添加变量:

MY_PROJECT_ROOT=/usr/any/path/you/want

然后在笔记本中

import os
from dotenv import load_dotenv
load_dotenv()  # this line loads .env file

然后输入您的代码

module_path = os.path.abspath(os.getenv('MY_PROJECT_ROOT'))
if module_path not in sys.path:
    sys.path.append(module_path)