Python 可以导入未安装的模块
Python can import a module that isn't installed
所以,我正在尝试打包我编写的 python 脚本,它有一个子模块,我们称它为 submodule
。文件夹结构如下所示:
cool_script/
setup.py
cool_script.py
submodule/
__init__.py
implementation.py
现在,经过多次 pip install .
和 pip install -e .
调用后,我的情况是 submodule
可以全局导入。无论在我系统的哪个位置,这总是有效的:
$ python3
[...]
>>> import submodule
>>> submodule.__file__
'/home/me/fake/path/cool_script/submodule/__init__.py'
但是我不知道为什么。
我做的包又被卸载了,pip在其索引中找不到子模块。 dist-packages 中也没有任何内容,我手动删除了仍然坐在那里的 cool_script.egg-link
:
$ ls /usr/local/lib/python3.4/dist-packages | ack cool
$ ls /usr/local/lib/python3.4/dist-packages | ack submodule
$
PYTHONPATH
也是空的:
$ echo $PYTHONPATH
$
为什么Python知道submodule
的位置?我怎样才能知道?
第一个运行python -c "import site; print(site.getsitepackages())"
。它将打印如下列表:
['/XXX/something/site-packages']
通常此列表中只有一个路径,它指向 pip
安装脚本的目录。如果你好奇,你可以 ls
进去:ls /XXX/something/site-packages/
.
不过,更有趣的是,当您使用开发人员安装 (a.k.a.pip install -e
) 时,pip
会在该目录中放置一个 "link" 文件。 "link" 文件以原始项目命名,末尾带有 .egg-link
扩展名。
所以您可能在该目录中有一个 cool_script.egg-link
文件。如果您尝试将其打印出来,您应该会发现其内容列出了模块的原始文件系统位置。类似于:
$ cat /XXX/something/site-packages/cool_script.egg-link
/home/me/fake/path/cool_script/
.
这就是 pip
记录它在开发者模式下安装了某些东西的方式,但并不是 Python 实际上知道如何找到您的模块的方式(那太容易了,对吧:-)).
Python 不知道 .egg-link
个文件,但它读取 site-packages
目录中的所有 .pth
个文件以获得 sys.path
的附加路径(*).因此,为了 Python 能够导入开发者模式安装,pip
将他们所有的路径写入一个通常称为 easy-install.pth
的 .pth
文件中(因为旧的 easy-install
工具实际上开创了该技术)。如果您打印出该文件,您将获得在开发者模式下安装的 所有 项目路径的列表:
$ cat /XXX/something/site-packages/easy-install.pth
/home/me/fake/path/cool_script/
/home/me/another/project/
并且您可以检查 easy-install.pth
中列出的所有路径是否确实已添加到您的 sys.path
。
(*) 从技术上讲,Python 中读取那些 .pth
文件的部分是通常在启动时自动导入的 site
模块。不过,有一个选项可以禁用 site
模块,例如使用 python -S
。在这种情况下,您会看到 sys.path
既不包含 site-packages
目录也不包含开发人员安装路径。
所以,我正在尝试打包我编写的 python 脚本,它有一个子模块,我们称它为 submodule
。文件夹结构如下所示:
cool_script/
setup.py
cool_script.py
submodule/
__init__.py
implementation.py
现在,经过多次 pip install .
和 pip install -e .
调用后,我的情况是 submodule
可以全局导入。无论在我系统的哪个位置,这总是有效的:
$ python3
[...]
>>> import submodule
>>> submodule.__file__
'/home/me/fake/path/cool_script/submodule/__init__.py'
但是我不知道为什么。
我做的包又被卸载了,pip在其索引中找不到子模块。 dist-packages 中也没有任何内容,我手动删除了仍然坐在那里的 cool_script.egg-link
:
$ ls /usr/local/lib/python3.4/dist-packages | ack cool
$ ls /usr/local/lib/python3.4/dist-packages | ack submodule
$
PYTHONPATH
也是空的:
$ echo $PYTHONPATH
$
为什么Python知道submodule
的位置?我怎样才能知道?
第一个运行python -c "import site; print(site.getsitepackages())"
。它将打印如下列表:
['/XXX/something/site-packages']
通常此列表中只有一个路径,它指向 pip
安装脚本的目录。如果你好奇,你可以 ls
进去:ls /XXX/something/site-packages/
.
不过,更有趣的是,当您使用开发人员安装 (a.k.a.pip install -e
) 时,pip
会在该目录中放置一个 "link" 文件。 "link" 文件以原始项目命名,末尾带有 .egg-link
扩展名。
所以您可能在该目录中有一个 cool_script.egg-link
文件。如果您尝试将其打印出来,您应该会发现其内容列出了模块的原始文件系统位置。类似于:
$ cat /XXX/something/site-packages/cool_script.egg-link
/home/me/fake/path/cool_script/
.
这就是 pip
记录它在开发者模式下安装了某些东西的方式,但并不是 Python 实际上知道如何找到您的模块的方式(那太容易了,对吧:-)).
Python 不知道 .egg-link
个文件,但它读取 site-packages
目录中的所有 .pth
个文件以获得 sys.path
的附加路径(*).因此,为了 Python 能够导入开发者模式安装,pip
将他们所有的路径写入一个通常称为 easy-install.pth
的 .pth
文件中(因为旧的 easy-install
工具实际上开创了该技术)。如果您打印出该文件,您将获得在开发者模式下安装的 所有 项目路径的列表:
$ cat /XXX/something/site-packages/easy-install.pth
/home/me/fake/path/cool_script/
/home/me/another/project/
并且您可以检查 easy-install.pth
中列出的所有路径是否确实已添加到您的 sys.path
。
(*) 从技术上讲,Python 中读取那些 .pth
文件的部分是通常在启动时自动导入的 site
模块。不过,有一个选项可以禁用 site
模块,例如使用 python -S
。在这种情况下,您会看到 sys.path
既不包含 site-packages
目录也不包含开发人员安装路径。