ssc*_*ssc 22 python path python-import
我正在为几个客户同时开发几个Python项目.我的项目文件夹结构的简化版本如下所示:
/path/
to/
projects/
cust1/
proj1/
pack1/
__init__.py
mod1.py
proj2/
pack2/
__init__.py
mod2.py
cust2/
proj3/
pack3/
__init__.py
mod3.py
Run Code Online (Sandbox Code Playgroud)
当我例如希望从使用功能proj1,我延伸sys.path通过/path/to/projects/cust1/proj1(例如,通过设置PYTHONPATH或添加.pth文件到site_packages文件夹或甚至修改sys.path直接地),然后导入模块是这样的:
>>> from pack1.mod1 import something
Run Code Online (Sandbox Code Playgroud)
当我处理更多项目时,不同的项目具有相同的包名称:
/path/
to/
projects/
cust3/
proj4/
pack1/ <-- same package name as in cust1/proj1 above
__init__.py
mod4.py
Run Code Online (Sandbox Code Playgroud)
如果我现在简单地扩展sys.path通过/path/to/projects/cust3/proj4,我仍然可以从进口proj1,而不是从proj4:
>>> from pack1.mod1 import something
>>> from pack1.mod4 import something_else
ImportError: No module named mod4
Run Code Online (Sandbox Code Playgroud)
我认为第二次导入失败的原因是Python只搜索sys.path找到pack1包的第一个文件夹,如果找不到该mod4模块则放弃.我在之前的一个问题中已经问过这个问题,请参阅具有相同名称的import python模块,但内部细节仍然不清楚.
无论如何,显而易见的解决方案是通过将项目目录转换为超级包来添加另一层命名空间限定:将__init__.py文件添加到每个proj*文件夹并从sys.path扩展的行中删除这些文件夹,例如
$ export PYTHONPATH=/path/to/projects/cust1:/path/to/projects/cust3
$ touch /path/to/projects/cust1/proj1/__init__.py
$ touch /path/to/projects/cust3/proj4/__init__.py
$ python
>>> from proj1.pack1.mod1 import something
>>> from proj4.pack1.mod4 import something_else
Run Code Online (Sandbox Code Playgroud)
现在我遇到了不同客户的不同项目具有相同名称的情况,例如
/path/
to/
projects/
cust3/
proj1/ <-- same project name as for cust1 above
__init__.py
pack4/
__init__.py
mod4.py
Run Code Online (Sandbox Code Playgroud)
mod4由于与以前相同的原因,尝试导入不再起作用了:
>>> from proj1.pack4.mod4 import yet_something_else
ImportError: No module named pack4.mod4
Run Code Online (Sandbox Code Playgroud)
按照之前解决此问题的相同方法,我将添加另一个包/命名空间层并将客户文件夹转换为超级超级包.
但是,这与我对项目文件夹结构的其他要求相冲突,例如
对某些项目文件夹的简化,更真实的描述如下所示:
/path/
to/
projects/
cust1/
proj1/
Development/
code/
javascript/
...
python/
pack1/
__init__.py
mod1.py
doc/
...
Release/
...
proj2/
Development/
code/
python/
pack2/
__init__.py
mod2.py
Run Code Online (Sandbox Code Playgroud)
我不知道如何满足python解释器对文件夹结构的要求以及我同时拥有的要求.也许我可以用一些符号链接创建一个额外的文件夹结构并使用它sys.path,但是看看我已经做出的努力,我感觉我的整个方法存在根本性的错误.在旁注中,我也很难相信python确实限制了我选择的源代码文件夹名称,因为它似乎在描述的情况下.
如何设置我的项目文件夹,sys.path以便如果项目和包具有相同的名称,我可以以一致的方式从所有项目导入?
ssc*_*ssc 17
这是我的问题的解决方案,虽然起初可能并不明显.
在我的项目中,我现在已经为每个客户引入了一个命名空间的约定.在每个客户文件夹(cust1,cust2等)中,都有一个__init__.py包含以下代码的文件:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
Run Code Online (Sandbox Code Playgroud)
__init__.py我的包中的所有其他文件都是空的(主要是因为我还没有时间去了解它们还有什么用).
正如这里所解释的那样,extend_path确保Python知道包中有多个子包,物理上位于其他地方 - 从我的理解 - 然后解释器在第一个包路径下找不到模块后不会停止搜索它遇到了sys.path,但搜索了所有路径__path__.
我现在可以以一致的方式访问所有项目之间的所有代码,例如
from cust1.proj1.pack1.mod1 import something
from cust3.proj4.pack1.mod4 import something_else
from cust3.proj1.pack4.mod4 import yet_something_else
Run Code Online (Sandbox Code Playgroud)
在缺点方面,我不得不创建一个更深入的项目文件夹结构:
/path/
to/
projects/
cust1/
proj1/
Development/
code/
python/
cust1/
__init__.py <--- contains code as described above
proj1/
__init__.py <--- empty
pack1/
__init__.py <--- empty
mod1.py
Run Code Online (Sandbox Code Playgroud)
但这对我来说似乎是非常可以接受的,特别是考虑到我需要付出很少的努力来维持这个惯例.sys.path延伸到/path/to/projects/cust1/proj1/Development/code/python这个项目.
在旁注中,我注意到__init__.py同一客户的所有文件中,首先出现的路径中的那个文件sys.path被执行,无论我从哪个项目导入的东西.
| 归档时间: |
|
| 查看次数: |
12087 次 |
| 最近记录: |