欢迎来到符号链接、PATH
的二进制可发现性和shebang #!/...
(*nix)的世界。
在深入了解所有内容之前,让我们先谈谈pip
是什么:
pip
既是Python模块(即python -m pip
(-m
表示模块)),也是一个二进制文件$ pip
。作为程序的二进制文件pip
是可选的,它不是必需的。但是,位于安装所有Python模块的site-packages
中的模块pip
则是绝对必需的!如果没有它,一切都将无法正常工作,或者更糟糕的是,您可能会使用来自您已安装的另一个Python版本的pip
模块,然后您真的会头破血流……
PATH变量
echo $PATH
(*nix)将显示类似以下内容:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
那么系统会通过终端首先在
/usr/local/bin
,然后是
/usr/bin
等目录中查找二进制文件。如果它在第一个查找的地方找到了,那就很好,不需要继续搜索了。你可以在不同的目录中拥有相同的二进制文件名称,但
PATH
的顺序才是关键,第二个将永远不会被执行。
我为什么要提到这个?假设你安装了多个版本的python
或pip
,并且把它们安装在错误的位置?路径顺序错了怎么办?那个二进制文件将无法按预期运行。
符号链接
你可以拥有不同版本的pip
和python
,它们彼此独立,这意味着即使你使用的是版本为3.8的python
,也不意味着你的pip
指向的是相同的python二进制文件。
一个快速检查的方法是:(适用于pip
)
$ ls -ls $(which python)
0 lrwxr-xr-x 1 root wheel 75 Jan 1 2020 /usr/bin/python -> ../../System/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7
您可以看到它正在使用系统版本的python
,如果我只运行python
,则会忽略任何其他版本,我可以通过指定版本号来“修复”这个问题,例如python3.8
...
您可以通过首先找出可用的二进制文件来解决此问题:
$ echo $PATH | sed 's/:/ /g' | xargs -n1 -I{} find {} -name 'python*' | grep -v 'config$'
/usr/local/bin/python3
/usr/local/bin/python3.9
/usr/local/bin/python3.8
/usr/bin/python3
/usr/bin/python
/usr/bin/python2
/usr/bin/pythonw
/usr/bin/pythonw2.7
/usr/bin/python2.7
假设我想将默认的python
设置为python3.8
,那么可以执行以下操作:
$ ln -s /usr/local/bin/python3.8 /usr/local/bin/python
$ hash -r
hash -r
告诉终端忘记之前找到的所有二进制文件,否则你的新符号链接将无法工作。
问:为什么不直接覆盖它呢?
你们中聪明的人可能会问,如果默认的 python
在 /usr/bin/python
中,为什么不直接使用覆盖呢?
$ ln -sf /usr/local/bin/python3.8 /usr/bin/python
/usr/bin/
是受保护的,而且乱搞系统偏好设置是很不好的形式。最好不要碰它,/usr/local/bin
是属于你(机器的用户)的。
Shebang #!/...
大多数情况下,你会发现pip
二进制文件(顺便说一下,它只是纯文本)像这样启动:
#!/usr/bin/env python
或者
#!/usr/local/bin/python3.9
这段文字的意思是,我是一个文本文件,需要使用以下可执行文件来运行。在第一个示例中,它使用系统来查找二进制文件
python
,就像您在终端中查找一样,请参见上面的
PATH
变量。第二个示例是系统使用的二进制文件的直接路径。
请记住,
pip
是一个模块,二进制文件
pip
实际上是这样说的:(稍作修改,使其尽可能基础,并说明一个观点)
import sys
from pip._internal.cli.main import main
sys.exit(main())
- 使用
python
二进制文件
- 导入
sys
模块以便稍后使用...
- 从
pip
模块导入 main
函数
- 运行
main
,无论它返回什么代码,请将其传递给 sys.exit(..)
,通常会返回 0
,但这不重要...只是一个 FYI
pip --version
命令返回以下结果:pip 20.0.2 from /root/<project-name>/my-virtual-env/lib/python3.8/site-packages/pip (python 3.8)
, 而运行python -m pip --version
命令则返回以下结果:pip 20.0.2 from /usr/lib/python3/dist-packages/pip (python 3.8)
。 - Osama Radwanwhich python
命令,它们返回的路径是否相同?如果是,则说明activate
没有更新路径,你需要手动运行hash -r
命令来更新虚拟环境。 - Javier Buzzipip
怎么样?你能展示一下路径吗? - Javier Buzzi