gpt4 book ai didi

python - pip install -e,Python 路径和命名空间包

转载 作者:行者123 更新时间:2023-12-01 06:35:40 25 4
gpt4 key购买 nike

我有一个像这样的包布局

myproject/
setup.py # contains package info for "myproject" package
myproject/ # contains various Python source files
deploy/ # contains non-package Python scripts for deployment tools
tests/
...

如果我发出 pip install -e . (这是在 conda 环境中),则从顶级 myproject 文件夹内部,则路径 /path/to/myproject 最终始终成为 sys.path 的一部分。

例如,如果我创建 myproject 存储库的新克隆并将其存储在新文件夹中,例如 myproject2,那么,然后在交互式环境中执行一些工作在该文件夹中的解释器中,我发现 sys.path 在启动时仍然会自动具有 /path/to/myproject

我的预感是这种情况正在发生,因为 pip install -e 会将文件从 /path/to/myproject 符号链接(symbolic link)到 site-packages 或其他合适的位置,Python 中的模块系统初始化必须做一些特殊处理,它遵循符号链接(symbolic link)并自动将源目录添加到路径中。

我遇到的问题是 deploy/ 中的(非包)脚本使用绝对导入来引用同一文件夹中的其他脚本(因为它们旨在从顶层执行) myproject),如何防止 Python 只查找使用 pip install -e< 的 myproject 的特定克隆存在的此文件夹的副本 从而出现在 Python 路径上?

已添加

在这种情况下,命名空间包会发生什么,这也让我感到困惑。例如,如果 deploy/ 文件夹没有 __init__.py 文件,但您正在执行 /path/to/myproject 中的内容> 工作目录(或者在 Python 路径中),那么在 Python 3.3+ 中它将被视为可以跨目录的命名空间包。

如果我两者都有会发生什么

/path/to/myproject   # which has been installed with pip install -e
/path/to/myproject2 # not installed, extra clone of the same project

然后,如果我在 /path/to/myproject2 中处理 deploy/ 脚本,它们最终是否会被视为还包含 /path/to/myproject/deploy/ 因为 /path/to/myproject 凭借 pip install -e 始终位于 Python 路径中?

那么最后一个问题是,这会对意外跨越两个目录的“大型”deploy 命名空间包内的绝对导入和相对导入以及导入优先级产生什么影响。

最佳答案

这是 easy-install.pth site-packages 目录中的文件对 sys.path 的值有影响。此效果不依赖于当前工作目录。我仍然不完全确定 *.egg-link 到底扮演什么角色文件在 site-packages 目录中播放(尽管它确实意味着(至少部分地)作为符号链接(symbolic link)的独立于平台的替代品)。

至于命名空间包...让我们考虑以下目录树:

.
├── alfa
│   ├── bravo
│   │   ├── one.py
│   │   └── zero.py
│   └── zero.py
├── foo
│   ├── bar
│   │   ├── two.py
│   │   └── zero.py
│   └── zero.py
└── src
├── alfa
│   ├── bravo
│   │   ├── three.py
│   │   └── zero.py
│   └── zero.py
└── foo
├── bar
│   ├── four.py
│   └── zero.py
├── __init__.py
└── zero.py

所有*.py 文件包含以下内容:

print(__name__, __file__)

请注意,只有一个包初始值设定项 src/foo/__init__.py

模块 alfa.bravo.onefoo.bar.two 是可导入的,因为当前目录始终位于 Python 解释器的搜索路径上(sys.路径):

$ python3 -c 'import alfa.bravo.one'
alfa.bravo.one /home/sinoroc/workspace/so-59682278/alfa/bravo/one.py
$ python3 -c 'import foo.bar.two'
foo.bar.two /home/sinoroc/workspace/so-59682278/foo/bar/two.py

但是导入 alfa.bravo.thirdfoo.bar.four 是不可能的:

$ python3 -c 'import alfa.bravo.three'
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'alfa.bravo.three'
$ python3 -c 'import foo.bar.four'
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'foo.bar.four'

出现这种情况是因为它们位于 src 目录中,而该目录不在 Python 的路径上:

$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/sinoroc/workspace/so-59682278/.venv/lib/python3.6/site-packages']

可以通过将目录位置写入解释器的 site-packages 目录中的 .pth 中,将目录添加到 Python 路径中:

$ echo "${PWD}/src" > '.venv/lib/python3.6/site-packages/test.pth'
$ python3 -c 'import sys; print(sys.path)'
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/sinoroc/workspace/so-59682278/.venv/lib/python3.6/site-packages', '/home/sinoroc/workspace/so-59682278/src']

现在可以导入 alfa.bravo.thirdfoo.bar.four:

$ python3 -c 'import alfa.bravo.three'
alfa.bravo.three /home/sinoroc/workspace/so-59682278/src/alfa/bravo/three.py
$ python3 -c 'import foo.bar.four'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.bar.four /home/sinoroc/workspace/so-59682278/src/foo/bar/four.py

由于命名空间包的存在,模块 alfa.bravo.one 仍然可以导入:

$ python3 -c 'import alfa.bravo.one'
alfa.bravo.one /home/sinoroc/workspace/so-59682278/alfa/bravo/one.py

但是由于 src 目录中的包 foo 有一个初始化程序,foo 不再是命名空间包,并且模块 foo.bar.two 无法导入:

$ python3 -c 'import foo.bar.two'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
Traceback (most recent call last):
File "<string>", line 1, in <module>
ModuleNotFoundError: No module named 'foo.bar.two'

现在对于zero模块来说有 pip 令人惊讶。当前目录和 src 目录中都有具有完全相同导入路径的模块:

$ python3 -c 'import alfa.zero'
alfa.zero /home/sinoroc/workspace/so-59682278/alfa/zero.py
$ python3 -c 'import alfa.bravo.zero'
alfa.bravo.zero /home/sinoroc/workspace/so-59682278/alfa/bravo/zero.py
$ python3 -c 'import foo.zero'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.zero /home/sinoroc/workspace/so-59682278/src/foo/zero.py
$ python3 -c 'import foo.bar.zero'
foo /home/sinoroc/workspace/so-59682278/src/foo/__init__.py
foo.bar.zero /home/sinoroc/workspace/so-59682278/src/foo/bar/zero.py

如果没有初始化的包(alfa),则导入当前工作目录中的版本。但如果有一个版本带有初始化程序 (foo),那么这就是导入的已初始化包中的版本。

注释

  • Python 3.6.9

关于python - pip install -e,Python 路径和命名空间包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59682278/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com