Python:从项目层次结构中同一级别的另一个目录导入模块

Posted

技术标签:

【中文标题】Python:从项目层次结构中同一级别的另一个目录导入模块【英文标题】:Python: import module from another directory at the same level in project hierarchy 【发布时间】:2013-12-03 06:16:56 【问题描述】:

我见过各种各样的例子和其他类似的问题,但我似乎找不到与我的场景完全匹配的例子。我觉得问这个完全是个傻瓜,因为有很多类似的问题,但我似乎无法让它“正确”工作。这是我的项目:

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |
        |------- Scripts/
        |           |
        |           |----- __init__.py
        |           |----- CreateUser.py
        |           |----- FindUser.py

如果我将“CreateUser.py”移动到主 user_management 目录,我可以轻松地使用:"import Modules.LDAPManager" 导入 LDAPManager.py --- 这有效。我不能做的(我想做的)是将 CreateUser.py 保留在 Scripts 子文件夹中,然后导入 LDAPManager.py。我希望通过使用"import user_management.Modules.LDAPManager.py" 来实现这一点。这行不通。简而言之,我可以让 Python 文件在层次结构中更深入地查看,但我无法让 Python 脚本向上引用一个目录并向下引用另一个目录。

请注意,我可以使用以下方法解决我的问题:

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import Modules.LDAPManager as LDAPManager

我听说这是不好的做法并且不鼓励。

Scripts 中的文件旨在直接执行(Scripts 中的 init.py 是否必要?)。我已经读过,在这种情况下,我应该使用 -m 标志执行 CreateUser.py。我对此进行了一些尝试,但似乎无法让 CreateUser.py 识别 LDAPManager.py。

【问题讨论】:

【参考方案1】:

如果我将 CreateUser.py 移动到主 user_management 目录,我可以 轻松使用:import Modules.LDAPManager 导入 LDAPManager.py --- 这行得通。

请,不要。这样,CreateUser 使用的 LDAPManager 模块将与通过其他导入导入的模块相同。当您在模块中或在酸洗/取消酸洗期间有一些全局状态时,这可能会产生问题。 避免仅因为模块恰好位于同一目录中而起作用的导入。

当你有一个包结构时,你应该:

使用相对导入,即如果CreateUser.pyScripts/ 中:

 from ..Modules import LDAPManager

请注意,PEP 8 不鼓励这种 (注意 过去 时态)只是因为旧版本的 python 不能很好地支持它们,但这个问题是多年前解决。 PEP 8 的当前 版本确实建议将它们作为绝对导入的可接受替代方案。我实际上喜欢它们在包中。

使用绝对导入使用整个包名Scripts/ 中的CreateUser.py):

 from user_management.Modules import LDAPManager

为了使第二个工作包user_management 应该安装在PYTHONPATH 内。在开发过程中,您可以配置 IDE 以便发生这种情况,而无需在任何地方手动添加对 sys.path.append 的调用。

我也觉得奇怪的是Scripts/ 是一个子包。因为在实际安装中,user_management 模块将安装在lib/ 目录中的site-packages 下(无论哪个目录用于在您的操作系统中安装库),而脚本应安装在bin/ 目录下(以包含适用于您的操作系统的可执行文件为准)。

事实上,我认为Script/ 甚至不应该在user_management 之下。它应该与user_management 处于同一级别。 这样,您不必必须使用-m,但您只需要确保可以找到包(这又是配置IDE、正确安装包或使用@的问题987654345@ 以使用正确的路径启动脚本)。


总之,将使用的层次结构是:

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |

 Scripts/  (*not* a package)
        |  
        |----- CreateUser.py
        |----- FindUser.py

那么CreateUser.pyFindUser.py的代码应该使用绝对导入来导入模块:

from user_management.Modules import LDAPManager

在安装过程中,请确保 user_management 最终位于 PYTHONPATH 中的某个位置,并且脚本位于可执行文件的目录中,以便它们能够找到模块。在开发过程中,您要么依赖 IDE 配置,要么启动 CreateUser.pyScripts/ 父目录添加到 PYTHONPATH(我的意思是包含 user_managementScripts 的目录):

PYTHONPATH=/the/parent/directory python Scripts/CreateUser.py

或者您可以全局修改PYTHONPATH,这样您就不必每次都指定。在 unix 操作系统(linux、Mac OS X 等)上,您可以修改其中一个 shell 脚本来定义 PYTHONPATH 外部变量,在 Windows 上,您必须更改环境变量设置。


附录我相信,如果您使用的是 python2,最好通过以下方式确保避免隐式相对导入:

from __future__ import absolute_import

在您的模块顶部。这样import X always 意味着导入 toplevel 模块X 并且永远不会尝试导入同一目录中的X.py 文件(如果该目录不在PYTHONPATH)。这样,only 进行相对导入的方法是使用 explicit 语法(from . import X),这更好(explicit 优于implicit )。

这将确保您永远不会碰巧使用“伪造的”隐式相对导入,因为这些会引发ImportError 明确表示出现问题。否则,您可能会使用不是您认为的那样的模块。

【讨论】:

如果你使用的是相对导入,你应该执行python -m user_management.Scripts.CreateUser 可以用from ..Modules import LDAPManager代替from .. import Modules吗? @dancab 不,这是不可能的【参考方案2】:

从 Python 2.5 开始,您可以使用

from ..Modules import LDAPManager

领先时期会让你在你的层次结构中“上升”一个级别。

有关导入,请参阅intra-package references 上的 Python 文档。

【讨论】:

【参考方案3】:

在“root”__init__.py你也可以做一个

import sys
sys.path.insert(1, '.')

这应该使两个模块都可以导入。

【讨论】:

【参考方案4】:

我也遇到了同样的问题。为了解决这个问题,我使用了export PYTHONPATH="$PWD"。但是,在这种情况下,您需要根据以下内容修改 Scripts 目录中的导入:

案例 1:如果您在 user_management 目录中,您的 scripts 应该使用这种样式 from Modules import LDAPManager 来导入模块。

案例 2:如果你不在user_management 1 级别,比如main,你的scripts 应该使用这种样式from user_management.Modules import LDAPManager 来导入模块。

【讨论】:

以上是关于Python:从项目层次结构中同一级别的另一个目录导入模块的主要内容,如果未能解决你的问题,请参考以下文章

无法使用从 python 中同一目录中的另一个文件访问的类

将 git 存储库向上移动一个层次结构级别

从层次结构级别和文本创建XML树[关闭]

将同一层次结构级别的两个节点与 PL/SQL 关联

是否可以从同一解决方案中的另一个项目引用 VS2005 网站项目?

如何根据 mdx 中的另一个维度层次结构过滤维度层次结构