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.py
在Scripts/
: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.py
和FindUser.py
的代码应该使用绝对导入导入模块:
from user_management.Modules import LDAPManager
在安装过程中,请确保user_management
在PYTHONPATH
某处以及可执行文件的目录中的脚本,以便它们能够find这些模块。 在开发过程中,您要么依赖于IDEconfiguration,要么启动CreateUser.py
将Scripts/
父目录添加到PYTHONPATH
(我的意思是包含user_management
和Scripts
的目录):
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, '.')
这应该使这两个模块都是可导入的。