unix Python如何找到sys.prefix(resp. sys.base_prefix)?

s6fujrry  于 2023-06-05  发布在  Unix
关注(0)|答案(2)|浏览(433)

罐头上写的是什么。
我已经解决了在使用虚拟环境时如何设置sys.prefix的问题(Python查找pyvenv.cfg文件[1])。
但是,我不太明白Python是如何找到sys.base_prefix的。
默认值为/usr/local(在Unix上)[2]。
但是,这似乎并没有在我的Mac上生效。
如下面的代码所示,后面是符号链接,在本例中,sys.base_prefix只是实际Python二进制文件上方的目录:

# Following symlinks to determinw where the actual hard link is
➜  tmp ls -l /usr/local/bin/python3
lrwxr-xr-x  1 jeffhemmen  admin  38 23 Jul 12:23 /usr/local/bin/python3 -> ../Cellar/python@3.8/3.8.5/bin/python3
➜  tmp ls -l /usr/local/Cellar/python@3.8/3.8.5/bin/python3
lrwxr-xr-x  1 jeffhemmen  staff  55 20 Jul 14:26 /usr/local/Cellar/python@3.8/3.8.5/bin/python3 -> ../Frameworks/Python.framework/Versions/3.8/bin/python3
➜  tmp ls -l /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3
lrwxr-xr-x  1 jeffhemmen  staff  9 20 Jul 14:26 /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3 -> python3.8
➜  tmp ls -l /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3.8
-rwxr-xr-x  1 jeffhemmen  staff  17704 23 Jul 12:23 /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3.8
# Printing sys.base_prefix for all these links
➜  tmp /usr/local/bin/python3 -c "import sys; print(sys.base_prefix)" 
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8
➜  tmp /usr/local/Cellar/python@3.8/3.8.5/bin/python3 -c "import sys; print(sys.base_prefix)"  
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8
➜  tmp /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3 -c "import sys; print(sys.base_prefix)"
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8
➜  tmp /usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/bin/python3.8 -c "import sys; print(sys.base_prefix)"
/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8

然而,在下面的例子中(同一台计算机,我的Mac),sys.base_prefix是完全不同的:

➜  tmp ls -l /usr/bin/python3 
-rwxr-xr-x  1 root  wheel  31488 10 Aug 21:56 /usr/bin/python3
➜  tmp /usr/bin/python3 -c "import sys; print(sys.base_prefix)" 
/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7

我在某个地方读到过,这取决于Python是如何安装的。这是否意味着sys.base_prefix实际上被编译成了二进制文件?如果没有,是否有一个文本文件(config,.py,...)在Python启动时读取的地方?

**额外问题:**何时/如何/为什么sys.exec_prefix实际上不同于sys.prefix(和/或sys.base_exec_prefix不同于sys.base_prefix`)?

42fyovps

42fyovps1#

documentation解释了如何设置值以及虚拟环境如何覆盖它。
这里是sys模块的source code,它似乎是在解释器状态初始化时设置的。我没有继续走下去。

fjnneemd

fjnneemd2#

**Python installation directory**是一个包含所有目录bin/include/lib/share/等的目录。任何Python安装都需要。如果你使用的是Ubuntu,它默认的Python安装目录是/usr。当我们创建一个虚拟环境时,会创建一个Python安装目录,该目录具有环境的名称。任何Python解释器,无论是否有环境,都需要这个目录结构才能正常工作。因此,使用venv(或任何其他工具,如pyenvpoetryconda)创建的Python环境将创建具有这些确切名称的目录。

例如,如果我们创建一个名为my_venv的Python虚拟环境,我们将拥有Python安装目录结构:

~/my_python_project$ python3 -m venv my_venv
~/my_python_project$ tree my_venv/ -L 1
. ## This is the "Python Installation directory" structure. Notice directories bin/, lib/ etc.
├── bin
├── etc
├── include
├── lib
├── lib64 -> lib
├── pyvenv.cfg
└── share

当我们在shell中输入python时,操作系统会遍历PATH环境变量,查找第一个名为'python'的可执行文件。一旦它找到了一个(它可能是一个符号链接,在这种情况下,它将不会被遵循),Python脚本将使用该解释器开始执行。Python脚本将自动执行的第一件事是询问操作系统它正在使用的解释器的位置,即在PATH环境变量中找到的解释器。有了这个位置,Python(更准确地说是site.py模块)将在可执行文件(或符号链接)所在的/bin目录的上一级查找名为pyenv.py的文件。如果找到,解释器会理解它是在虚拟环境中;如果没有找到,则解释器将理解它不在虚拟环境中。
在虚拟环境中,如果pyvenv.cfg文件包含home键,解释器将使用它来设置sys.base_prefixsys_prefix为:

  1. sys.base_prefix将保存用于创建此虚拟环境的Python installation directory的路径。为此,解释器将查看pyvenv.cfg中的home键。此键将保存用于创建此虚拟环境的Python可执行文件所在目录的路径。如果该可执行文件恰好是一个符号链接,则会跟踪它,直到真实的的可执行文件。托管真实的可执行文件所在的bin/目录的目录将是用于构建此环境的Python可执行文件的Python安装目录。例如:
~/my_python_projects$ cat ./my_venv/pyvenv.cfg
home = /usr/local/bin   ## this is because this Python virtual environment was created from the executable
                        ## /usr/local/bin/python3, which is a symlink to /usr/bin/python3.8. 
                        ## Thus sys.base_prefix will be /usr
include-system-site-packages = false
version = 3.8.10
~/my_python_projects$ ls -l /usr/local/bin/python3
lrwxrwxrwx 1 root root 18 mar  2  2022 /usr/local/bin/python3 -> /usr/bin/python3.8
~/my_python_projects$ source ./my_venv/bin/activate  ## activate the virtual environment
(my_venv) ~/my_python_projects$ python3 -c "import sys;print(sys.base_prefix)"
/usr
  1. sys.prefix将指向包含pyvenv.cfg文件的目录(如果存在),即虚拟环境的Python安装目录(如果我们正在使用虚拟环境)。如果不使用虚拟环境,则与sys.base_prefix相同。
(my_venv) ~/my_python_projects$ python3 -c 'import sys;print(sys.base_prefix);print(sys.prefix)'
/usr  ## sys.base_prefix
/home/carl/my_python_projexts/env_no_ga  ## sys.prefix

请注意,这两个“基目录”都具有Python安装的目录结构,即。目录binincludelib等。还要注意,如果我们没有使用虚拟环境,sys.base_prefixsys.base都将被设置为操作系统的Python安装目录。在我的例子中,我使用的是Ubuntu 20.04,所以当不使用虚拟环境时,这些变量是/usr
同样从Python文档hereI deduce中,其他两个变量sys.prefixsys.base_prefix被设置为:

  1. sys.base_exec_prefix:如果在虚拟环境中,它将与sys.base_prefix相同,即用于创建虚拟环境的Python解释器的Python安装目录。如果不在虚拟环境中,它将是OS Python安装目录。
  2. sys.exec_prefix:如果在虚拟环境中,它将与sys.prefix相同,即虚拟环境的Python安装目录。如果不在虚拟环境中,它将是OS Python安装目录。
    换句话说,通过default,它们将始终分别与sys.base_prefixsys.prefix相同。
    阅读了引用的关于sys.base_prefixsys.prefixsys.base_exec_prefixsys.exec_prefix的Python文档,我得出的结论是,所有这些变量最初都设置在操作系统的Python安装目录中。之后,如果模块site.py确定我们处于虚拟环境中,则会继续如上所述更改它们。
    我还没有发现的是,用不同的名字定义所有这些变量,但它们具有相同的值,背后的原理是什么。

参考书目

  1. Python and the Module Search Path马克·贾米森
  2. Python文档在这里

相关问题