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


87

我已经看到了各种各样的示例和其他类似的问题,但是似乎找不到与我的方案完全匹配的示例。我觉得这很愚蠢,因为有很多类似的问题,但是我似乎无法“正确”地解决这个问题。这是我的项目:

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

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

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

Answers:


66

如果移至CreateUser.pyuser_management主目录,则可以轻松使用:import Modules.LDAPManager导入LDAPManager.py ---可以。

拜托,不要。通过这种方式,LDAPManager所用模块CreateUser不会是一样的一个通过其他进口进口。当您在模块中具有某些全局状态时,或在酸洗/酸洗过程中,这可能会产生问题。避免仅由于模块恰好位于同一目录中而进行的导入。

具有包结构时,您应该:

  • 使用相对导入,即如果在CreateUser.pyScripts/

     from ..Modules import LDAPManager
    

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

  • 使用完整的包名称CreateUser.py在中Scripts/)使用绝对导入:

     from user_management.Modules import LDAPManager
    

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

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

实际上我相信Script/甚至都不应该失败user_management。它应该处于的相同级别user_management。这样你就不会有使用-m,但你只需要确保包可以发现(这又是配置IDE,正确安装包或使用的问题PYTHONPATH=. python Scripts/CreateUser.py与正确的路径启动脚本)。


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

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.pyScripts/父目录添加到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 总是意味着要导入顶层模块,X并且永远不会尝试导入X.py同一目录中的文件(如果该目录不在中PYTHONPATH)。这样,进行相对导入的唯一方法是使用显式语法(from . import X),后者更好(显式优于隐式)。

这将确保您永远不会使用“伪造的”隐式相对进口,因为这些进口会ImportError清楚地表明某些问题是错误的。否则,您可以使用与您想像的模块不同的模块。


如果您使用相对导入,则应执行python -m user_management.Scripts.CreateUser
mononoke '17

14

从Python 2.5开始,您可以使用

from ..Modules import LDAPManager

领导期使您“提升”了层次结构。

有关导入的信息,请参见有关包内参考的Python文档。


3

在“根目录”中,__init__.py您还可以

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.