python导入路径:不同文件夹中具有相同名称的包

python导入路径:不同文件夹中具有相同名称的包,python,path,python-import,Python,Path,Python Import,我正在同时为几个客户开发几个Python项目。我的项目文件夹结构的简化版本如下所示: /path/ to/ projects/ cust1/ proj1/ pack1/ __init__.py mod1.py proj2/ pack2/ __init__.py mod2.py cust2/

我正在同时为几个客户开发几个Python项目。我的项目文件夹结构的简化版本如下所示:

/path/
  to/
    projects/
      cust1/
        proj1/
          pack1/
            __init__.py
            mod1.py
        proj2/
          pack2/
            __init__.py
            mod2.py
      cust2/
        proj3/
          pack3/
            __init__.py
            mod3.py
>>> from pack1.mod1 import something
/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
例如,当我想使用
proj1
中的功能时,我通过
/path/to/projects/cust1/proj1
扩展
sys.path
(例如,通过设置
PYTHONPATH
或将
.pth
文件添加到
site\u packages
文件夹,甚至直接修改
sys.path
)然后像这样导入模块:

/path/
  to/
    projects/
      cust1/
        proj1/
          pack1/
            __init__.py
            mod1.py
        proj2/
          pack2/
            __init__.py
            mod2.py
      cust2/
        proj3/
          pack3/
            __init__.py
            mod3.py
>>> from pack1.mod1 import something
/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
当我处理更多的项目时,不同的项目有相同的包名:

/path/
  to/
    projects/
      cust3/
        proj4/
          pack1/    <-- same package name as in cust1/proj1 above
            __init__.py
            mod4.py
我认为第二次导入失败的原因是Python只搜索
sys.path
中的第一个文件夹,在那里它找到了
pack1
包,如果没有找到
mod4
模块,它就会放弃。我在前面的一个问题中问过这个问题,请看,但我仍然不清楚内部细节

无论如何,显而易见的解决方案是通过将项目目录转换为超级包来添加另一层名称空间限定:向每个
proj*
文件夹添加
\uuuuu init\uuuuu.py
文件,并从扩展
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
现在我遇到的情况是,不同客户的不同项目具有相同的名称,例如

/path/
  to/
    projects/
      cust3/
        proj1/    <-- same project name as for cust1 above
          __init__.py
          pack4/
            __init__.py
            mod4.py
按照以前解决此问题的相同方法,我将添加另一个包/名称空间层,并将客户文件夹转换为超级包

但是,这与我对项目文件夹结构的其他要求相冲突,例如

  • 用于维护多个代码行的开发/发布结构
  • 其他类型的源代码,如JavaScript、SQL等
  • 源文件以外的其他文件,如文档或数据
一些项目文件夹的简化程度较低、更真实的描述如下所示:

/path/
  to/
    projects/
      cust1/
        proj1/
          pack1/
            __init__.py
            mod1.py
        proj2/
          pack2/
            __init__.py
            mod2.py
      cust2/
        proj3/
          pack3/
            __init__.py
            mod3.py
>>> from pack1.mod1 import something
/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
我不知道如何才能满足python解释器对文件夹结构的要求以及我同时拥有的文件夹结构的要求。也许我可以用一些符号链接创建一个额外的文件夹结构,并在
sys.path
中使用它,但看看我已经在做的工作,我觉得我的整个方法有一些根本性的错误。另一方面,我也很难相信python真的限制了我对源代码文件夹名称的选择,就像在所描述的例子中那样


如何设置项目文件夹和
sys.path
,以便在存在同名项目和包的情况下,以一致的方式从所有项目导入?

您应该使用优秀的和工具。

是解决我问题的方法,尽管一开始可能并不明显

在我的项目中,我现在引入了每个客户一个名称空间的约定。在每个客户文件夹(
cust1
cust2
等)中,都有一个包含以下代码的
\uuuu init\uuuuuuuuuuuy.py
文件:

import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
我的软件包中的所有其他
\uuuuu init\uuuuuuuuuuuy.py
文件都是空的(主要是因为我还没有时间找到其他的处理方法)

如前所述,
extend_path
确保Python知道一个包中有多个子包,物理上位于其他位置,并且据我所知,解释器在
sys.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
另一方面,我不得不创建一个更深层的项目文件夹结构:

/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
/path/
到/
计划/
卡斯特1/
proj1/
发展/
代码/
蟒蛇/
卡斯特1/

__init_uuuy.py如果您不小心从一个客户/项目导入了另一个客户/项目的代码而没有注意到会发生什么?当你交付时,它几乎肯定会失败。我会采用一种惯例,一次为一个项目设置PYTHONPATH,而不是试图让您曾经编写的所有内容同时变得重要

您可以为每个项目使用包装器脚本来设置PYTHONPATH和启动python,或者在切换项目时使用脚本来切换环境


当然,有些项目与其他项目(您提到的那些库)有依赖关系,但是如果您希望客户能够同时导入多个项目,那么您必须安排名称不冲突。只有当PYTHONPATH上有多个项目不应该一起使用时,才会出现此问题。

我正在使用它们,但它们只提供解决方案,只要我在同一客户的项目之间导入。如果需要从更广泛的范围导入,那么在系统python env中的虚拟环境中也会出现相同的冲突。另外,尽管我非常喜欢virtualenv,但从我的角度来看,它弥补了python解释器的一个主要缺点。我真的是唯一一个遇到这个问题的人吗?嗯,你不应该这样在项目之间共享功能。如果它们需要共享一些实现,请考虑将它提取为库并将它们包含在两个项目SHMM中,因此我问如何做某事,而响应是不做它?那不是我所希望的。巧合的是,我实际上正在按照你的建议做——我将功能提取到一个库中,并在其他项目中使用它——这正是导入路径问题产生的地方。我得到的印象是,这是一个其他人都在以某种方式解决的问题,我将不得不接受此导入限制,例如,引入一个约定,仅在同一客户的包之间导入(并且每个客户维护一个虚拟环境)。