我知道我们可以使用绝对路径来处理问题,但我想知道是否有更好的方法,特别是当我们考虑分发代码时
详细问题来了
项目结构
/a
utils.py
/b/b.json
/c/c.ipynb
在 a.py 中,有一行
open("./b/b.jon", "r")
在 c.ipynb 中,有一行
import utils.py
(该行自 pycharm 广告 /a
进入系统路径以来一直有效)
但是,如果我在
c.ipynb中运行
import utils.py
,则会出现错误 FileNotFoundError: [Errno 2] No such file or directory: ./b/b.json
我明白这是预期的,因为当前工作目录是
/a/c
,而不是/a
。所以解析a.py
中的相对路径时,就会变成/a/c/b/b.json
。但是有没有更优雅的方法,而不是设置像PROJECT_ROOT
这样的全局变量来处理这个问题呢? (__file__
在这种情况下不起作用,因为它是jupyter笔记本。)
一般来说,开发项目和处理相对导入的最佳实践是什么,特别是在处理 jupyter 笔记本时(我目前的理解是修改 PYTHONPATH 进行相对导入,但同样,文件读取问题怎么办?)
你的问题有很严重的问题,很不清楚。 (也许,一些可重现的代码片段会对您的情况有所帮助?)
有了这个,我认为按照你的建议设置一个全局变量将是正确的方法,因为Jupyter Notebook只会在当前目录中查找通常创建的包/库/模块导入(特别是像简单如另一个 Python 文件)。[1]
现在解决问题:
/a
目录下:/a
𝗮.𝗽𝘆
utils.py
/b/b.json
/c/c.ipynb
open("./b/b.𝗷𝘀𝗼𝗻", "r")
在a.py中,有一行
open("./b/b.jon", "r")
c.ipynb会抛出
FileNotFoundError: [Errno 2] No such file or directory: ./b/b.json
(根据您的问题),是 a.py 使用 open("./b/b.json", "r")
创建文件流请求。如果我在 c.ipynb 中运行 import utils.py,则会出现错误
FileNotFoundError: [Errno 2] No such file or directory: ./b/b.json
/.
或 /..
以使笔记本可以访问它。然后手动将外部目录添加到笔记本中的系统路径(这是这个答案中建议的技术)。我理解这是预期的,因为当前工作目录是
,而不是/a。所以解析a.py中的相对路径时,就会变成/a/c
./a/c/b/b.json
pathlib.Path
和os.path()
是你的(最好的)朋友。但是有没有更优雅的方式[...]?
由于您没有提供最小的代码示例,我的实验设置如下:
# \a -> a.py
import os
import json
from pathlib import Path
def print_json():
# Relative path; Mr. Jupyter hates this so don't do it
# json_file = open("./b/b.json")
# Absolute JSON file path
json_file_path = Path(os.getcwd() + "/.././/b/b.json").__str__()
json_file = open(json_file_path)
json_object = json.load(json_file)
return json.dumps(json_object, indent=1)
# \a -> utils.py
def add_mult(x, y, z):
return x * y + z
b.json 将包含一些简单的文本,如 JSON.org 上所示(或简单地构成您的文本)。
然后在c.ipynb中,我们有:
# \a\c -> c.ipynb
import sys, os
# From \c, step out to \a, step out yet again outside \a
import_path = os.path.abspath(os.path.join("..\.."))
# Add the obtained parent path to sys path to force-expose \a contents
if import_path not in sys.path: sys.path.append(import_path + "\\")
# Import away!
from a.utils import add_mult
from a.a import print_json
# 1 * 2 + 3
ans = add_mult(1,2,3)
print(f"1 * 2 + 3 = {ans}\n")
# Print formatted contents of \a\b\b.json
json_text = print_json()
print(json_text)