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

我已经看到了各种各样的例子和其他类似的问题,但我似乎无法find一个完全符合我的情况的例子。 我觉得自己好像总是问这个问题,因为有这么多类似的问题,但我似乎无法“正确地”做到这一点。 这是我的项目:

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 —这是可行的。 我不能做的(我想做的)是在Scripts子文件夹中保存CreateUser.py,然后导入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。

如果我将CreateUser.py移动到主user_management目录,我可以轻松地使用: import Modules.LDAPManager导入LDAPManager.py —这可以工作。

不要 。 通过这种方式, CreateUser使用的LDAPManager模块将不会与通过其他导入导入的模块相同。 当模块中有一些全局状态或酸洗/取出时,这可能会产生问题。 避免仅仅因为模块碰巧在同一目录中而导入的工作。

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

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

      from ..Modules import LDAPManager 

    请注意,这 (注意过去式) PEP 8只是因为老版本的python不能很好地支持它们,但是这个问题在几年前就已经被解决了。 目前版本的PEP 8 确实表明它们是绝对import的可接受替代品。 我真的喜欢它们里面的包。

  • 使用绝对导入使用整个包名称 (在Scripts/ CreateUser.py ):

      from user_management.Modules import LDAPManager 

为了让第二个工作包的user_management应该安装在PYTHONPATH里面。 在开发过程中,您可以configurationIDE以使其发生,而无需在任何地方手动添加对sys.path.append调用。

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

事实上,我相信Script/甚至不应该在user_management下。 它应该与user_management处于同一级别。 通过这种方式,您不必使用-m ,但只需确保可以find软件包(这也是configurationIDE,正确安装软件包或使用PYTHONPATH=. python Scripts/CreateUser.py用正确的path启动脚本)。


总之, 将使用的层次是:

 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_managementPYTHONPATH某处以及可执行文件的目录中的脚本,以便它们能够find这些模块。 在开发过程中,您要么依赖于IDEconfiguration,要么启动CreateUser.pyScripts/父目录添加到PYTHONPATH (我的意思是包含user_managementScripts的目录):

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

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


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

 from __future__ import absolute_import 

在你的模块的顶部。 通过这种方式, import X 总是意味着导入顶层模块X并且不会尝试导入同一目录中的X.py文件(如果该目录不在PYTHONPATH )。 这样做相对导入的唯一方法是使用显式语法( from . import X ),这是更好的( 显式比隐式更好 )。

这将确保您永远不会碰巧使用“伪”隐式相对导入,因为这会引发ImportError清楚地表明出现了错误。 否则,你可以使用一个不是你认为的模块。

从Python 2.5开始,你可以使用

 from ..Modules import LDAPManager 

领先的时期把你提升到一个层面。

有关导入的内部包引用 ,请参阅Python文档。

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

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

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