Ubuntu 20.04的Python默认版本是3.8,符合正常使用要求。 而Ubuntu 18.04上是3.6版本,更早的16.04上则是3.5版本。 而Debian的稳定版buster,如今才3.7,Deepin也同样。 在以前,Python两年发一版时,Debian这个节奏还勉强能接受;现在一年一版,就显得过于落后了。 目前(2021年5月),Python最新稳定版是3.9,3.10还处于alpha阶段。
如果因为某些原因,需要在各发行版上使用其它Python版本,就需要额外安装。 其实,deb系里,说的就是Deepin。 Ubuntu并不算落后,Debian也可以用unstable或testing的源,唯有Deepin菜得难以接受。
环境准备 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 sudo apt-get install -y \ build-essential \ curl \ git \ libbz2-dev \ libffi-dev \ liblzma-dev \ libncurses5-dev \ libncursesw5-dev \ libreadline-dev \ libsqlite3-dev \ libssl-dev \ llvm \ python-openssl \ tk-dev \ wget \ xz-utils \ zlib1g-dev
以上是Ubuntu中,下载、编译Python源码所需要的环境。 后面的几种方案,都共同依赖于这些软件包。
从源码编译安装 1 2 3 4 5 6 7 8 9 cd /tmpwget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz tar -xf Python-3.9.5.tar.xz cd Python-3.9.5./configure --enable-optimizations --prefix=$HOME /.python/3.9.5 make -j8 make install cd $HOME /.pythonln -s 3.9.5 default
尽量不要使用--enable-optimizations,虽然能更快的编译但会缺少一些依赖比如yolo所需的_bz2(/python_path/python_version/lib/python_version/lib-dynload/)
如果要为所有用户全局安装,可以把安装位置选择在/opt/python/,然后sudo make install。 安装完成后,把安装位置添加到PATH前面,覆盖系统版本:
1 2 3 4 export PATH=$HOME /.python/default/bin:$PATH export PATH=/opt/python/default/bin:$PATH
如果要支持多版本,以上那个default的软链接就能产生价值了。 在相同目录下安装其它版本,然后把软连接替换过去就行。
进入 Python 源码根目录,执行以下命令:
1 2 3 ./configure make make install
Python 将会被编译,并安装在默认目录中。若您希望将 Python 安装在特定目录,则需要在一开始修改 configure 命令为:
1 ./configure --prefix=<Python要安装到的目录(绝对路径)>
在指定目录中:
默认情况下,编译的 Python 是静态链接(libpython3.7m.a)。如果希望编译的 Python 是动态链接(libpython3.7m.so),则需要在一开始修改configure 命令为:
1 ./configure --enable-shared
如需重新编译,请首先执行:
update-alternatives ¶ 有没有办法可以免配置PATH,不用手动操作软链接,也能自动管理多个Python的版本?
有,update-alternatives欢迎你。
新增候选 在源码make编译完成后,sudo make install到/opt/python/3.9.5目录。 然后执行以下命令:
1 2 sudo update-alternatives --install /usr/local/bin/python3 python3 /opt/python/3.9.5/bin/python3 80
update-alternatives的原理是,在指定的<link>位置,创建软链接<link> -> /etc/alternatives/<name>。 然后再创建软链接/etc/alternatives/<name> -> <path>。 由于在PATH中,/usr/local/bin默认排在/usr/bin前面,所以这个新的python3会被优先使用,实现对系统版本的替代。
<priority>是指,在同时存在多个版本时,默认使用哪一个。 数值越大,优先级越高。
更新候选 同样的命令,可以更新既有候选的优先级。
1 sudo update-alternatives --install /usr/local/bin/python3 python3 /opt/python/3.9.5/bin/python3 50
也可以增加新的候选,比如系统原有的/usr/bin/python3。
1 sudo update-alternatives --install /usr/local/bin/python3 python3 /usr/bin/python3 100
查询候选 通过--query <name>,可以查询某个候选的情况。
1 2 3 4 5 6 7 8 9 10 11 12 $ update-alternatives --query python3 Name: python3 Link: /usr/local/bin/python3 Status: auto Best: /usr/bin/python3 Value: /usr/bin/python3 Alternative: /opt/python/3.9.5/bin/python3 Priority: 50 Alternative: /usr/bin/python3 Priority: 100
以上就是刚才设置的两个python3的候选版本。 如果--install了更多版本,也可在此查到。
如果要查询python3以外的全部候选,可以运行update-alternatives --all,但不推荐 。 这个信息很多,而且还需要处理优先级相同的一些情况。 因此,还不如去ls /etc/alternatives。
调整候选版本 在自动模式下,/usr/alternatives/python3会链接到优先级最高的那个版本。 如果需要手动调整,需要使用--set <name> <path>。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 $ sudo update-alternatives --set python3 /opt/python/3.9.5/bin/python3update-alternatives: using /opt/python/3.9.5/bin/python3 to provide /usr/local/bin/python3 (python3) in manual mode $ update-alternatives --query python3 Name: python3 Link: /usr/local/bin/python3 Status: manual Best: /usr/bin/python3 Value: /opt/python/3.9.5/bin/python3 Alternative: /opt/python/3.9.5/bin/python3 Priority: 50 Alternative: /usr/bin/python3 Priority: 100 $ /usr/local/bin/python3 --version Python 3.9.5
--set后,再用--query查看,可以发现Status变成了manual,即手动模式。 用--set可以对python3的版本进行任意切换。 如果要改回去,可以用--auto <name>。
1 2 $ sudo update-alternatives --auto python3update-alternatives: using /usr/bin/python3 to provide /usr/local/bin/python3 (python3) in auto mode
删除 如果需要删除某个版本,可以使用--remove <name> <path>:
1 sudo update-alternatives --remove python3 /opt/python/3.9.5/bin/python3
如果需要删除某个候选,可以使用--remove-all <name>:
1 sudo update-alternatives --remove-all python3
pyenv 除了在系统中管理多个Python版本以外,如何发现、下载、编译,也是个问题。 pyenv 是这方面最流行的解决方案。
尽管久闻大名,但孤对这个方案还是无比抗拒,所以拖到最近才研究。 要注意的是,它只是开发环境的方案,不适合做生产环境。
安装pyenv 1 curl https://pyenv.run | bash
网络正常的话,以上安装是便捷无痛的。 然而,其中很重要的一步,就是去GitHub上clone它的几个代码库下来。
配置pyenv 安装完成后,还需要把以下内容,加到~/.bashrc中。
1 2 3 4 export PYENV_ROOT="$HOME /.pyenv" export PATH="$PYENV_ROOT /bin:$PYENV_ROOT /shims:$PATH " export PYENV_SHELL="bash" source "$PYENV_ROOT /completions/pyenv.bash"
另一个选择是用eval,如果你不在意它做了什么。 而且,上面的配置去掉了对pyenv-virtualenv的支持。 所以,如果需要傻瓜式完整配置,那么可以使用下面这些。
1 2 eval "$(pyenv init -) " eval "$(pyenv virtulenv-init -) "
pyenv的可执行文件,在$PYENV_ROOT/bin下。 而它所管理的默认Python相关可执行文件,包括python、pydoc、pip等,会软链接到$PYENV_ROOT/shims下。 除了安装以外,在版本管理上,它和update-alternatives使用了类似的思路和技术。
pyenv安装新版本 列出可选安装的Python版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 $ pyenv install --list Available versions: 2.1.3 2.2.3 2.3.7 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.6.6 2.6.7 2.6.8 2.6.9 2.7.0 2.7-dev 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.15 2.7.16 2.7.17 2.7.18 3.0.1 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.0 3.4-dev 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.4.7 3.4.8 3.4.9 3.4.10 3.5.0 3.5-dev 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 3.5.9 3.5.10 3.6.0 3.6-dev 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9 3.6.10 3.6.11 3.6.12 3.6.13 3.7.0 3.7-dev 3.7.1 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.7.10 3.8.0 3.8-dev 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.8.10 3.9.0 3.9-dev 3.9.1 3.9.2 3.9.3 3.9.4 3.9.5 3.10.0b1 3.10-dev 3.11-dev activepython-2.7.14 activepython-3.5.4 activepython-3.6.0 anaconda-1.4.0 anaconda-1.5.0 anaconda-1.5.1 anaconda-1.6.0 anaconda-1.6.1 anaconda-1.7.0 anaconda-1.8.0 anaconda-1.9.0 anaconda-1.9.1 anaconda-1.9.2 anaconda-2.0.0 anaconda-2.0.1 anaconda-2.1.0 anaconda-2.2.0 anaconda-2.3.0 anaconda-2.4.0 anaconda-4.0.0 anaconda2-2.4.0 anaconda2-2.4.1 anaconda2-2.5.0 anaconda2-4.0.0 anaconda2-4.1.0 anaconda2-4.1.1 anaconda2-4.2.0 anaconda2-4.3.0 anaconda2-4.3.1 anaconda2-4.4.0 anaconda2-5.0.0 anaconda2-5.0.1 anaconda2-5.1.0 anaconda2-5.2.0 anaconda2-5.3.0 anaconda2-5.3.1 anaconda2-2018.12 anaconda2-2019.03 anaconda2-2019.07 anaconda3-2.0.0 anaconda3-2.0.1 anaconda3-2.1.0 anaconda3-2.2.0 anaconda3-2.3.0 anaconda3-2.4.0 anaconda3-2.4.1 anaconda3-2.5.0 anaconda3-4.0.0 anaconda3-4.1.0 anaconda3-4.1.1 anaconda3-4.2.0 anaconda3-4.3.0 anaconda3-4.3.1 anaconda3-4.4.0 anaconda3-5.0.0 anaconda3-5.0.1 anaconda3-5.1.0 anaconda3-5.2.0 anaconda3-5.3.0 anaconda3-5.3.1 anaconda3-2018.12 anaconda3-2019.03 anaconda3-2019.07 anaconda3-2019.10 anaconda3-2020.02 anaconda3-2020.07 anaconda3-2020.11 graalpython-20.1.0 graalpython-20.2.0 graalpython-20.3.0 graalpython-21.0.0 graalpython-21.1.0 ironpython-dev ironpython-2.7.4 ironpython-2.7.5 ironpython-2.7.6.3 ironpython-2.7.7 jython-dev jython-2.5.0 jython-2.5-dev jython-2.5.1 jython-2.5.2 jython-2.5.3 jython-2.5.4-rc1 jython-2.7.0 jython-2.7.1 jython-2.7.2 micropython-dev micropython-1.9.3 micropython-1.9.4 micropython-1.10 micropython-1.11 micropython-1.12 micropython-1.13 micropython-1.14 miniconda-latest miniconda-2.2.2 miniconda-3.0.0 miniconda-3.0.4 miniconda-3.0.5 miniconda-3.3.0 miniconda-3.4.2 miniconda-3.7.0 miniconda-3.8.3 miniconda-3.9.1 miniconda-3.10.1 miniconda-3.16.0 miniconda-3.18.3 miniconda2-latest miniconda2-3.18.3 miniconda2-3.19.0 miniconda2-4.0.5 miniconda2-4.1.11 miniconda2-4.3.14 miniconda2-4.3.21 miniconda2-4.3.27 miniconda2-4.3.30 miniconda2-4.3.31 miniconda2-4.4.10 miniconda2-4.5.1 miniconda2-4.5.4 miniconda2-4.5.11 miniconda2-4.5.12 miniconda2-4.6.14 miniconda2-4.7.10 miniconda2-4.7.12 miniconda3-latest miniconda3-2.2.2 miniconda3-3.0.0 miniconda3-3.0.4 miniconda3-3.0.5 miniconda3-3.3.0 miniconda3-3.4.2 miniconda3-3.7.0 miniconda3-3.7-4.8.2 miniconda3-3.7-4.8.3 miniconda3-3.7-4.9.2 miniconda3-3.8.3 miniconda3-3.8-4.8.2 miniconda3-3.8-4.8.3 miniconda3-3.8-4.9.2 miniconda3-3.9.1 miniconda3-3.9-4.9.2 miniconda3-3.10.1 miniconda3-3.16.0 miniconda3-3.18.3 miniconda3-3.19.0 miniconda3-4.0.5 miniconda3-4.1.11 miniconda3-4.2.12 miniconda3-4.3.11 miniconda3-4.3.14 miniconda3-4.3.21 miniconda3-4.3.27 miniconda3-4.3.30 miniconda3-4.3.31 miniconda3-4.4.10 miniconda3-4.5.1 miniconda3-4.5.4 miniconda3-4.5.11 miniconda3-4.5.12 miniconda3-4.6.14 miniconda3-4.7.10 miniconda3-4.7.12 miniforge3-4.9.2 miniforge3-4.10 pypy-c-jit-latest pypy-dev pypy-stm-2.3 pypy-stm-2.5.1 pypy-1.5-src pypy-1.6 pypy-1.7 pypy-1.8 pypy-1.9 pypy-2.0-src pypy-2.0 pypy-2.0.1-src pypy-2.0.1 pypy-2.0.2-src pypy-2.0.2 pypy-2.1-src pypy-2.1 pypy-2.2-src pypy-2.2 pypy-2.2.1-src pypy-2.2.1 pypy-2.3-src pypy-2.3 pypy-2.3.1-src pypy-2.3.1 pypy-2.4.0-src pypy-2.4.0 pypy-2.5.0-src pypy-2.5.0 pypy-2.5.1-src pypy-2.5.1 pypy-2.6.0-src pypy-2.6.0 pypy-2.6.1-src pypy-2.6.1 pypy-4.0.0-src pypy-4.0.0 pypy-4.0.1-src pypy-4.0.1 pypy-5.0.0-src pypy-5.0.0 pypy-5.0.1-src pypy-5.0.1 pypy-5.1-src pypy-5.1 pypy-5.1.1-src pypy-5.1.1 pypy-5.3-src pypy-5.3 pypy-5.3.1-src pypy-5.3.1 pypy-5.4-src pypy-5.4 pypy-5.4.1-src pypy-5.4.1 pypy-5.6.0-src pypy-5.6.0 pypy-5.7.0-src pypy-5.7.0 pypy-5.7.1-src pypy-5.7.1 pypy2-5.3-src pypy2-5.3 pypy2-5.3.1-src pypy2-5.3.1 pypy2-5.4-src pypy2-5.4 pypy2-5.4.1-src pypy2-5.4.1 pypy2-5.6.0-src pypy2-5.6.0 pypy2-5.7.0-src pypy2-5.7.0 pypy2-5.7.1-src pypy2-5.7.1 pypy2.7-5.8.0-src pypy2.7-5.8.0 pypy2.7-5.9.0-src pypy2.7-5.9.0 pypy2.7-5.10.0-src pypy2.7-5.10.0 pypy2.7-6.0.0-src pypy2.7-6.0.0 pypy2.7-7.0.0-src pypy2.7-7.0.0 pypy2.7-7.1.0-src pypy2.7-7.1.0 pypy2.7-7.1.1-src pypy2.7-7.1.1 pypy2.7-7.2.0-src pypy2.7-7.2.0 pypy2.7-7.3.0-src pypy2.7-7.3.0 pypy2.7-7.3.1-src pypy2.7-7.3.1 pypy3-2.3.1-src pypy3-2.3.1 pypy3-2.4.0-src pypy3-2.4.0 pypy3.3-5.2-alpha1-src pypy3.3-5.2-alpha1 pypy3.3-5.5-alpha-src pypy3.3-5.5-alpha pypy3.5-c-jit-latest pypy3.5-5.7-beta-src pypy3.5-5.7-beta pypy3.5-5.7.1-beta-src pypy3.5-5.7.1-beta pypy3.5-5.8.0-src pypy3.5-5.8.0 pypy3.5-5.9.0-src pypy3.5-5.9.0 pypy3.5-5.10.0-src pypy3.5-5.10.0 pypy3.5-5.10.1-src pypy3.5-5.10.1 pypy3.5-6.0.0-src pypy3.5-6.0.0 pypy3.5-7.0.0-src pypy3.5-7.0.0 pypy3.6-7.0.0-src pypy3.6-7.0.0 pypy3.6-7.1.0-src pypy3.6-7.1.0 pypy3.6-7.1.1-src pypy3.6-7.1.1 pypy3.6-7.2.0-src pypy3.6-7.2.0 pypy3.6-7.3.0-src pypy3.6-7.3.0 pypy3.6-7.3.1-src pypy3.6-7.3.1 pypy3.6-7.3.2-src pypy3.6-7.3.2 pypy3.6-7.3.3-src pypy3.6-7.3.3 pypy3.7-c-jit-latest pypy3.7-7.3.2-src pypy3.7-7.3.2 pypy3.7-7.3.3-src pypy3.7-7.3.3 pypy3.7-7.3.4 pyston-2.2 stackless-dev stackless-2.7-dev stackless-2.7.2 stackless-2.7.3 stackless-2.7.4 stackless-2.7.5 stackless-2.7.6 stackless-2.7.7 stackless-2.7.8 stackless-2.7.9 stackless-2.7.10 stackless-2.7.11 stackless-2.7.12 stackless-2.7.14 stackless-3.2.2 stackless-3.2.5 stackless-3.3.5 stackless-3.3.7 stackless-3.4-dev stackless-3.4.2 stackless-3.4.7 stackless-3.5.4 stackless-3.7.5
以上排在最前面、没有什么前缀的,就是官方版本。 除了官方CPython版本以外,它还支持anaconda、pypy、jython等其它Python实现。 这也是它最大的优势。
安装某个具体的版本,只需要复制上面列出的值即可。 比如3.9.5:
1 2 3 4 5 $ pyenv install 3.9.5 Downloading Python-3.9.5.tar.xz... -> https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tar.xz Installing Python-3.9.5... Installed Python-3.9.5 to /home/yanqd0/.pyenv/versions/3.9.5
pyenv选择版本 在运行方面,pyenv 设计了一个复杂的金字塔结构,包括四层:
shell,开一个新的shell,里面是指定版本的Python环境。
local,在当前目录创建一个.python-version环境。当前目录及其子目录内,Python环境都会自动使用这个指定版本。
global,在用户级的~/.pyenv/version中维护一个全局版本。在前两种情况以外的场景,使用系统默认版本。
system,如果连~/.pyenv/version文件都没有,比如在另一个用户,则使用系统版本。
这其实把问题搞复杂了,仿佛有了这些,大家就不用使用虚拟环境似的。 pyenv shell的设计,和pipenv shell类似,因此也被后者这类替代。 pyenv local是一个自找麻烦的功能,建议不要使用。 否则,在不同目录下Python版本不同,受伤的总会是自己。 一般,一个Python项目的开发环境会使用独立的虚拟环境。
因此,只有pyenv global值得一用。 它读写一体,用法如下:
1 2 3 4 5 $ pyenv global system $ pyenv global 3.9.5 $ pyenv global 3.9.5
如果要查询当前真正可用的Python版本是什么,可用使用pyenv version或pyenv versions。
1 2 3 4 5 6 7 8 $ pyenv versions system 3.8.10 * 3.9.5 (set by /home/yanqd0/.pyenv/version) pypy3.7-7.3.4 pyston-2.2 $ pyenv version 3.9.5 (set by /home/yanqd0/.pyenv/version)
其中,带*的就是当前版本,默认是system,也即系统原先的版本。 如果没有用pyenv local自找麻烦,那边pyenv version和pyenv global的结果应该是一致的。
pyenv的其它子命令 通过pyenv --help,可查看其它功能。 但除了几个低频的查询子命令以外,不推荐 使用pyenv的其它子命令。
1 2 3 4 5 6 $ pyenv root /home/yanqd0/.pyenv $ pyenv which python /home/yanqd0/.pyenv/versions/3.9.5/bin/python $ pyenv prefix /home/yanqd0/.pyenv/versions/3.9.5
显然,这些查询命令有点用。 但如果清楚了其中软链接的把戏,其实也没什么用。
包括shell、activate、virtualenv等子命令,都和虚拟环境有关。 这个方案,解决不了所有问题,因此还是让其它更专业的虚拟环境方案来解决吧。 这方面,可以参考本站的《Python中的虚拟环境及其工作原理 》。 让pyenv 专心管好多版本的Python即可。
pyenv的shims 尽管pyenv 的shims,看上去和update-alternatives的/etc/alternatives目录差不多,但其实更复杂。 ~/.pyenv/shims中的每一个文件,内容都是一样的,比如~/.pyenv/shims/python3:
1 2 3 4 5 6 7 8 #!/usr/bin/env bash set -e[ -n "$PYENV_DEBUG " ] && set -x program="${0##*/} " export PYENV_ROOT="/home/yanqd0/.pyenv" exec "/home/yanqd0/.pyenv/libexec/pyenv" exec "$program " "$@ "
显然,它不是一个软链接,而是劫持了用户的命令行调用,用自己中转了一道。 也因此,它才能在运行时动态地判断是使用shell、local、global、system中的哪个版本。
pyenv-install+update-alternatives pyenv 默认是一个用户级的解决方案。 也就是说,对root和其它用户是无效的。 但是略经调整,也能成为一个系统级的方案。
如果不使用pyenv的虚拟环境功能,也不使用复杂的shell、local、global多层级版本管理, 那么可以放弃shims技术,只用pyenv install功能。
用update-alternatives来安装pyenv ¶ 在前面安装到/opt/pyenv的基础上,使用update-alternatives可以在不修改系统PATH的情况下,使用pyenv安装的多个Python版本。
1 2 curl https://pyenv.run | sudo PYENV_ROOT="/opt/pyenv" bash sudo update-alternatives --install /usr/local/bin/pyenv pyenv /opt/pyenv/bin/pyenv 100
环境变量等配置,也要变成全局操作。 把以下内容写入/etc/profile.d/pyenv.sh中:
1 2 3 export PYENV_ROOT="/opt/pyenv" export PYENV_SHELL="bash" source "$PYENV_ROOT /completions/pyenv.bash"
此外,为了让sudo能支持它,需要让sudo中存在这些环境变量。 把以下内容写到/etc/sudoers.d/pyenv:
1 Defaults env_keep += "PYENV_ROOT PYENV_SHELL"
这样,pyenv对其它用户也可用。 这也可以避免因root用户的Python版本不同而导致sudo出现一些诡异问题。 但是,执行安装等写操作时,需要使用sudo。
1 2 pyenv install --list sudo pyenv install 3.8.10
而且,按照本文的配置,其虚拟环境等插件功能无效。
用update-alternatives来管理Python版本 在利用sudo pyenv install安装了想要的版本后,可以用以下命令将其添加为候选。 这样,多个不同来源的Python版本就能统一管理了。
当然,update-alternatives相比pyenv 的shims技术,还是有很多不足。 比如,如果要统一管理pydoc等命令,需要使用--slave,这略显麻烦。
1 2 3 4 5 6 7 8 9 sudo update-alternatives \ --install /usr/local/bin/python3 python3 /usr/bin/python3 100 \ --slave /usr/local/bin/pydoc3 pydoc3 /usr/bin/pydoc3 sudo update-alternatives \ --install /usr/local/bin/python3 python3 /opt/pyenv/versions/3.8.10/bin/python3 200 \ --slave /usr/local/bin/pydoc3 pydoc3 /opt/pyenv/versions/3.8.10/bin/pydoc3 sudo update-alternatives \ --install /usr/local/bin/python3 python3 /opt/pyenv/versions/3.9.5/bin/python3 300 \ --slave /usr/local/bin/pydoc3 pydoc3 /opt/pyenv/versions/3.9.5/bin/pydoc3
在Python多版本环境下,pip一般通过python -m pip来运行,会更准确。
总结 从源码安装、手动管理,到update-alternatives,再到pyenv ,又回归pyenv-install+update-alternatives。 本文算是把Linux下,Python多版本管理的主要骚操作都讲完了。 此外,也稍微提点了一下原理。