从并行文件夹导入Python

0 投票
2 回答
94 浏览
提问于 2025-04-14 18:22

我搞不清楚怎么从一个平行的文件夹导入。

从同一个目录导入是没问题的:

project_folder
  -subfolder1
    -my_prog.py
    -credentials.py

credentials.py 文件里包含

api_key = "supersecretapikey"

而 my_prog.py 文件里包含

import credentials

当我运行 $ python my_prog.py 时,这一切都正常。

不过,我想把 credentials 移到另一个子文件夹,像这样:

project_folder
  -subfolder1
    -my_prog.py
  -subfolder2
    -credentials.py

在这种设置下,我无法让导入工作。我尝试了一个很明显的方法,就是:

from ..subfolder2 import credentials

结果出现了一个错误

ImportError: attempted relative import with no known parent package

这个错误我不太明白。

我试着在 project_folder、subfolder1 和 subfolder2 里放 __init__.py 文件,但似乎没有什么变化。

我不想使用环境变量,因为需要在远程服务器上运行这个。

我使用的是 Python 3.12.2

2 个回答

0

指令 from A import B 是用来从模块 A 中导入一个组件(比如子模块、函数、变量等)B。这和目录结构或路径没有关系,这也是你关心的问题。

Python 解释器查找要导入的模块的地方列在系统变量 sys.path 中(这是一个字符串列表)。你可以使用标准的 list.append() 方法来添加你想要导入自己模块的目录(参考 sys.path 文档):

import sys
sys.path.append('C:/Users/Sebastian/Dropbox/project_folder/subfolder2')
import credentials   # reads file cedentials.py in subfolder2

注意在 Windows 上也要使用 "/",或者使用 r'c:\Users\...' 来避免 \ 被当作转义字符,或者使用 "c:\\Users\\..."

上面的简单例子其实是过于简化了,只是为了说明系统是如何以及在哪里搜索要导入的文件。你肯定不想使用一个固定的绝对路径。所以你应该按照以下方式来获取父文件夹 "project_folder" 的路径,然后再获取 "sister" 子文件夹的路径:

import os
myfolder = os.getcwd()  # typically, "C:\\...\\project_folder\\subfolder1"
project_folder = os.path.dirname(myfolder)  # should be "C:\\...\\project_folder"
sys.path.append( project_folder + "\\subfolder2" )
import credentials

另外,你可能更喜欢使用 __file__ 变量,而不是 os.getcwd(),因为 __file__ 会给你当前代码所在文件的位置,而不是主程序的位置(主程序可能会把这个文件作为一个(子)模块包含进来)。

此外,你可能想把新位置插入到 sys.path 列表的开头,这样系统会先在这里查找,也可以在导入完成后将其移除。

附注:以上内容回答了“如何从平行文件夹导入”的问题。如果要获取凭证或其他数据,import 可能不是最好的选择,你应该搜索“如何读取数据文件”。

0

在和一个使用相对导入的文件,比如 ..otherModule,放在同一个地方运行 Python 脚本是行不通的。你不能通过相对导入来访问父目录(或者它的子目录)里的文件,因为脚本运行的位置决定了你能访问的范围。使用相对导入时,代码会认为基础目录是你运行脚本的地方,而不是文件本身所在的位置。

解决这个问题的方法是,先进入 project_folder 文件夹,然后在那儿运行脚本(使用 "python -m subfolder1.myprog")。另外,在 my_prog.py 文件中,把 ..subfolder2 改成 subfolder2。这样在 project_folder 中,相对导入 subfolder2 就能按你预期的方式工作了。一般来说,绝对导入会更好,因为它能消除这种混淆。

撰写回答