从父文件夹导入模块

1086

我正在运行Python 2.5。

这是我的文件夹树:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(每个文件夹中都有__init__.py,为了可读性已省略)

我应该如何从life模块内部导入nib模块?我希望能在不修改sys.path的情况下完成。

注意:正在运行的主模块位于ptdraft文件夹中。


2
罗斯: 我看过那里了。我该怎么办?我已经有__init__.py文件了。S.Lott: 我不知道该如何检查... - Ram Rachum
4
在shell中输入“echo $PYTHONPATH”,在Python中输入“import sys; print sys.path”,这两个命令可以输出当前系统的Python模块搜索路径。相关信息可以在此链接查看:http://docs.python.org/tutorial/modules.html?highlight=pythonpath#modules - S.Lott
20
我强烈推荐跳过所有关于 sys.path 或者 PYTHONPATH 的答案,查看 np8 的优秀回答。是的,它很长。是的,看起来需要很多工作。但这是唯一一个真正正确且干净地解决问题的答案。 - Aran-Fey
9
可执行的伪代码到底发生了什么?为什么在Python中从父文件夹导入模块如此麻烦?这太荒谬了。 - eric
15
为什么这件事这么麻烦?读完所有的讨论和答案后,仍然没有合理简单的解决方案。 - Apollys supports Monica
显示剩余10条评论
32个回答

33
在一个Jupyter Notebook中(使用JupyterLab或Jupyter Notebook打开)
只要您正在使用Jupyter Notebook,这个简短的解决方案可能会有用:
%cd ..
import nib

即使没有__init__.py文件也可以工作。

我在Linux和Windows 7上使用Anaconda 3进行了测试。


9
在导入之后添加“%cd -”是否有意义,这样笔记本的当前目录就不会改变。 - Dror
1
这对于需要导入使用相对路径导入其他模块的模块时非常有帮助。 - Jianyu

25

我发现以下方法可以从脚本的父目录导入包。在这个例子中,我想从app.db包中导入env.py中的函数。

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)

1
一个漂亮的一行代码:sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))) - juzzlin
1
修改 sys.path 通常是一个不好的想法。你需要一些方法(例如,PYTHONPATH)让你的库对于其他代码可访问(否则它就不是真正的库);一直使用那个就好了! - Davis Herring

18
之前提到的解决方案也是可以的。这个问题的另一个解决方案是:
如果你想从顶层目录导入任何东西。那么,
from ...module_name import *

此外,如果您想从父目录导入任何模块。那么,请:
from ..module_name import *

另外,如果你想从父目录导入任何模块。那么,

from ...module_name.another_module import *

这样,如果你想要导入特定的方法,就可以使用这种方式。


16
这似乎应该是可以的,但由于某些原因,它不能像上面的sys.path.append这样工作,我无法像这样导入我的库。这是我在开始谷歌搜索之前尝试做的事情 :) 好的,就是这个 ValueError: attempted relative import beyond top-level package. - juzzlin
1
我进行了一些测试,似乎 from ... import name 不是指“从顶层导入name”,而是指“从父级的父级导入name”。我创建了一个嵌套的目录结构 a1/.../a9,其中每个目录都包含一个 __init__.py 文件,使用 from . import next_dir 导入下一个目录。最后一个目录有一个文件,其中 from ....... import b 然后导入 a1/a2/a3/b。(在 Python 3.8.2 中测试) - Cubi73
我们在图书馆测试中使用了这个解决方案。被采纳的答案确实是正确的做法,但如果我理解正确的话,那将需要暴露我们不想要的模块。 - Higgs
@juzzlin 那是另一个问题。请参阅 https://dev59.com/fV0a5IYBdhLWcg3wJVvv。 - Karl Knechtel

17

两行最简解决方案

import os, sys
sys.path.insert(0, os.getcwd()) 

如果 parent 是你的工作目录,你想从 child 脚本中调用其他子模块。

你可以在任何脚本中从 parent 目录导入所有子模块并执行它,如下:

python child_module1/child_script.py

2
这是唯一一个对我有效,并且最适合我的用例的方法:从测试文件夹中导入主方法。 - Noah Gary

13

我认为你可以在特定的例子中尝试这个,但是在Python 3.6.3中:

Enter image description here


好的,您可以点击此链接下载「import_case」以查看源代码 case_repo - Gin

12
为了完整性,这里有一个简单的解决方案。就是像这样将 life.py 作为模块运行:

cd ptdraft
python -m simulations.life.life

你可以通过这种方式从 nib.py 导入任何东西,因为 ptdraft 目录在路径中。


这是一个非常好的方法,适用于那些不想混乱sys.path或环境变量如PYTHONPATH的人,有关-m的更多细节,您可以查看此stackoverflow线程 - Ham
如果你正在使用VSCode,可以通过在 https://dev59.com/CrXna4cB1Zd3GeqPOqgp 配置相应参数实现自动化执行。 - Alex Li

11

对我而言,获取父目录的最短且我最喜欢的一行代码是:

sys.path.append(os.path.dirname(os.getcwd()))
或者:
sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd()返回当前工作目录的名称,os.path.dirname(directory_name)返回传递的目录的目录名称。

实际上,在我看来,Python项目架构应该采用这样的方式:子目录中的任何模块都不会使用父目录中的任何模块。如果发生这样的情况,就值得重新考虑项目树。

另一种方法是将父目录添加到PYTHONPATH系统环境变量中。


2
+1 提到需要重新构建项目的可能性(而不是在问题上进行hack) - semore_1267
1
这不是获取父级,而是获取当前的。 - Ricky Levi
这是一个不好的想法,因为它依赖于当前目录而不是文件的位置,因此它会根据您运行脚本的位置而执行不同的操作。 - jamesdlin

11
import sys
sys.path.append('../')

11
从不同的目录执行时,这将无法正常工作。 - Shatlyk Ashyralyyev

6

我有一个专门针对Git存储库的解决方案。

首先,我使用了sys.path.append('..')和类似的解决方案。如果您正在导入自己使用sys.path.append('..')导入文件的文件,则会出现问题。

然后,我决定始终附加Git存储库的根目录。一行代码看起来像这样:

sys.path.append(git.Repo('.', search_parent_directories=True).working_tree_dir)

或者更详细地说:

import os
import sys
import git
def get_main_git_root(path):
    main_repo_root_dir = git.Repo(path, search_parent_directories=True).working_tree_dir
    return main_repo_root_dir
main_repo_root_dir = get_main_git_root('.')
sys.path.append(main_repo_root_dir)

根据仓库的根目录,导入应该是什么?
import ptdraft.nib

或者

import nib

顺便说一下:这是安装git库的方法:pip install GitPython - Thomas R

6
在Linux系统中,您可以从“life”文件夹创建一个指向nib.py文件的软链接。然后,您可以像这样简单地导入它: ```python import nib ```
import nib

1
这个回答值得更多的关注。符号链接方法比本帖中大多数答案干净得多,而且数量级更高。然而,这是我第一次看到有人建议使用它。 - Mahmoud
4
我不同意。这是一种不具备可移植性的解决方案,同时将文件系统层和Python源代码混合在了一起。 - problemofficer - n.f. Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接