如何将Python源代码分割成单独的目录?

6 投票
2 回答
3022 浏览
提问于 2025-04-16 00:09

以下是我公司 "foo.com" 使用的一些不同的 Python 包:

com.foo.bar.web
com.foo.bar.lib
com.foo.zig.web
com.foo.zig.lib
com.foo.zig.lib.lib1
com.foo.zig.lib.lib2

这是传统的将源代码存储在磁盘上的方法:

pysrc/
  com/
    foo/
      bar/
        web/
        lib/
      zig/
        web/
        lib/
          lib1/
          lib2/

PYTHONPATH=pysrc

但是为了更好地组织(不同的团队、不同的版本控制等等),我们想要这样存储:

bar/
  pysrc/
    com/
      foo/
        bar/
          web/
          lib/
zig/
  pysrc/
    com/
      foo/
        zig/
          web/
          lib/
            lib1/
            lib2/

PYTHONPATH=bar/pysrc:zig/pysrc

问题是:

这种第二种组织方式有没有什么问题呢?

比如说,如果我们使用 import com.foo,Python 会在哪里寻找 __init__.py 文件呢?

把这些目录做成符号链接(symlink)合理吗?例如:

pysrc/
  com/
    foo/
      bar/ -> symlink to /bar/pysrc/com/foo/
      zig/ -> symlink to /zig/pysrc/com/foo/

欢迎任何关于代码组织的一般建议。

2 个回答

3

在阅读PEP 420 页面时,发现你可以在共享包中添加以下的 __init__.py 文件:

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

所以你的目录结构应该是这样的(带 * 标记的 __init__.py 文件包含上面的代码):

myroot/
├── bar
│   └── pysrc
│       └── com
│           ├── ****__init__.py****
│           └── foo
│               ├── ****__init__.py****
│               └── bar
│                   ├── __init__.py
│                   ├── lib
│                   │   ├── __init__.py
│                   │   └── barlib.py
│                   └── web
│                       ├── __init__.py
│                       ├── barweb.py
└── zig
    └── pysrc
        └── com
            ├── ****__init__.py****
            └── foo
                ├── ****__init__.py****
                └── zig
                    ├── __init__.py
                    ├── lib
                    │   ├── __init__.py
                    │   ├── lib1
                    │   │   ├── __init__.py
                    │   │   └── ziblib1.py
                    │   └── lib2
                    │       ├── __init__.py
                    │       └── ziblib2.py
                    └── web
                        ├── __init__.py
                        ├── zigweb.py

设置 Python 路径指向你的 com/ 目录:

barPath=/myroot/bar/pysrc/
zigPath=/myroot/zig/pysrc/
export PYTHONPATH=$PYTHONPATH:$barPath:$zigPath

为了测试(我在 2.7.14 和 3.6.4 上尝试过):

from com.foo.bar.web.barweb import BarWeb
from com.foo.zig.web.zigweb import ZigWeb
b = BarWeb()
z = ZigWeb()

如果没有 __init__.py 的代码,会得到:

ImportError: No module named zig.web.zigweb
4

Python会按照顺序检查sys.path中的路径(这其中包括PYTHONPATH和其他一些路径),寻找com.foo这个包。它会使用找到的第一个包,而不会考虑其他的包。这和Perl或Java不同,后者会把多个包的命名空间合并在一起。虽然你可以对__path__做一些操作来改变这种行为,但默认情况下,Python的规则是“先找到的优先”。

只要你把com.foo.bar的所有内容放在bar/文件夹里,把com.foo.zig的所有内容放在zig/文件夹里,第二种布局就不会有问题。

撰写回答