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.py
在Scripts/
中:
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.py
和FindUser.py
的代码应该使用绝对导入来导入模块:
from user_management.Modules import LDAPManager
在安装过程中,请确保 user_management
最终位于 PYTHONPATH
中的某个位置,并且脚本位于可执行文件的目录中,以便它们能够找到模块。在开发过程中,您要么依赖 IDE 配置,要么启动 CreateUser.py
将 Scripts/
父目录添加到 PYTHONPATH
(我的意思是包含 user_management
和 Scripts
的目录):
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:从项目层次结构中同一级别的另一个目录导入模块的主要内容,如果未能解决你的问题,请参考以下文章