前言


Ubuntu 上的 Python 之所以容易配乱,是因为「Python」在这台机器上有两个身份:一个是操作系统自己用的那个(包管理器安装的 /usr/bin/python3),另一个是你作为开发者要用的那个。前者被系统工具依赖,后者应该由你自己创建和维护。把这两个身份混为一谈,就是各种「装了个包结果系统设置界面打不开」事故的根源。


最常见的误解是「sudo pip install 很方便」。它确实方便,代价是往系统解释器里塞进一个 Ubuntu 发行版并不知情、也没测试过的包,可能覆盖系统工具依赖的版本。另一个误解是「装个新版本 Python 就是把老版本替换掉」。实际上你更可能需要的是并存:系统继续用它的,你用你的。


本文按「原则 → 正确做法 → 装新版 → 切换方式与其风险」的顺序讲。必须说明:本机没有 Python 解释器,本文不在 Ubuntu 上,也没有运行过本文任何命令,所有命令与机制均按 Python 官方文档、Linux 手册页与通用发行版约定写出;涉及第三方软件源与第三方工具的部分(例如换个源装新版 Python),请以该来源的官方说明为准。文中不给出任何性能数字。


一、原则:别动系统 Python


系统解释器承担着大量不显眼的工作:包管理器的辅助脚本、桌面环境的某些组件、系统自带的各类工具,都可能依赖 /usr/bin/python3 以及它 site-packages 里由发行版打包好的模块。因此有两条铁律:



  1. 不要往系统解释器里随意装第三方包(尤其是用 pip 且加 sudo)。

  2. 不要把系统解释器的指向改到别的版本上。


这两条不是风格建议,而是被官方机制固化下来的规则。较新的 Ubuntu 会启用 PEP 668「Marking Python base environments as『externally managed』」:系统解释器被标记为「受管环境」,此时对系统 Python 执行 pip install 会被拒绝并给出提示。这不是 pip 坏了,而是一道保护,正确的反应是改用虚拟环境,而不是加参数强行绕过。


那要在系统层面装模块怎么办?用发行版的包管理器,也就是 apt。Ubuntu 把很多常用库都打包成了 python3-xxx 形式的包;Python 官方文档在讲 Unix 平台安装附加组件时给的就是这个路子:向用户推荐用系统包管理器安装,例如 Debian 与 Ubuntu 用户用 apt,Fedora 与 RHEL 用户用 dnf,SUSE 与 openSUSE 用户用 zypper,Alpine 用户用 apk。




你想要的正确做法不要做



项目要用第三方库建虚拟环境,在环境内装用 sudo pip install 装进系统

系统层面需要一个模块apt install python3-xxx用 pip 覆盖发行版打的包

换个 Python 版本做开发装共存的新版本,用它建环境改掉系统 python3 的指向

命令行要用 Python写 python3,或写具体版本依赖 python 这个名字



二、日常开发的标准姿势:虚拟环境


标准库自带的 venv 是默认选择(官方文档从 3.5 起就推荐用它创建虚拟环境)。流程只有四步:创建、激活、装依赖、退出。


# 1) 创建环境;目录名约定用 .venv
python3 -m venv .venv

# 2) 激活:POSIX 下激活脚本在 bin 目录里
source .venv/bin/activate

# 3) 在环境内安装,用 python -m pip 而不是裸 pip
python -m pip install --upgrade pip
python -m pip install requests

# 4) 退出
deactivate

有两个 Ubuntu 特有的细节要注意:



  • venv 在 Ubuntu 上通常需要单独装一个包。如果创建环境时报出与 ensurepip 不可用有关的错误,原因多半是发行版把这个组件拆出去了,装 python3-venv 即可,然后用 python3 -m venv 重建环境。

  • pip 也不一定预装。系统层面若需要,用 apt install python3-pip;但在虚拟环境里更应该用 python -m pip,它保证「装包的解释器」和「跑脚本的解释器」是同一个。


另一个容易被忽略的点:虚拟环境不是「非激活不可」。官方文档明确说,你可以直接写该环境解释器的完整路径来执行脚本,效果一样。这在与 systemd、cron 这类不经过 shell 的场景配合时特别有用——直接指向 .venv/bin/python 比想办法让它们「先激活」要可靠得多。


# 适用于 Python 3.8+:进虚拟环境后自查,确认「装」和「用」是同一个解释器
import sys

print("解释器路径:", sys.executable)
print("环境前缀 :", sys.prefix)
print("是否在虚拟环境内:", sys.prefix != sys.base_prefix)
print("site-packages 搜索位置:")
for p in sys.path:
if "site-packages" in p:
print(" ", p)

三、需要更新的 Python 版本时怎么办


三条路,各有取舍:




路线做法优点风险



发行版仓库apt install python3.x(仓库里有的版本)与系统集成好、有安全更新版本落后于上游

第三方软件源例如给 Ubuntu 增加一个提供新版 Python 的 PPA,再用 apt 安装安装方便、可以并存非官方渠道,质量与维护看该来源,以该来源的官方说明为准

自建用版本管理工具,或从官方源码自行构建完全可控、可并存需要自己维护依赖与升级



选择的关键不是「哪个版本最新」,而是「它会不会覆盖系统解释器」。第三方的 PPA 通常会以独立版本号的形式安装(例如装成 python3.12 而不是替换 python3),这才是安全的形态。加源之前务必做两件事:确认该来源确实是你要用的那个、以及确认它安装的是并存版本而不是替换品。具体命令请以该软件源自己的官方说明为准,本文不写死。


装好并存版本后,正确的用法是用它来创建虚拟环境,而不是把它接到系统的 python3 上:


# 用并存版本的解释器建环境,之后这个项目就一直用环境里的 python
/usr/bin/python3.12 -m venv .venv
source .venv/bin/activate
python -V

这样做的结果是:项目之间可以各用各的版本,系统解释器毫发无损。


update-alternatives:用法与风险


update-alternatives 是 Debian 系用来管理「同一个通用名对应多个候选实现」的机制。它的手册页讲得很清楚,几个要点值得记住:



  • 链接组有两种模式:自动模式下,系统会在安装、卸载软件包时自动决定指向哪一个(按优先级,优先级最高者胜出);手动模式下,系统保留管理员的设置,不再自动改动。链接组第一次被引入系统时处于自动模式。

  • 常用命令:--install link name path priority 用于添加一组候选项;--config name 列出该组所有候选并让你选,选过之后该组可能就不再是自动模式了,要用 --auto 才能回到自动;不想交互就用 --set;--display name 显示该组的模式(auto 或 manual)、当前指向以及所有候选。

  • 手册特别强调:提供同一个文件的多个软件包必须协作使用这套机制,也就是说,随意改它属于越权操作。


对 Python 来说,风险非常直白:系统里那个 python3 的名字背后站着的是一大批系统工具。用 update-alternatives 把 python3 指向另一个版本,等于让这些工具去用它们没被测过的解释器。因此:



  • 不要用 update-alternatives 去改系统 python3 的指向。 需要别的版本,就用那个版本的完整路径去建虚拟环境。

  • 如果你确实要管理自己安装的某组命令(比如某几个工具的不同版本),--install + --config + --display 这套流程可以用,并且记得用 --display 复查当前是自动还是手动模式,别让一次交互选择留下你不知道的手动配置。


四、排障时的固定检查顺序


遇到「这个包明明装了却导入不到」「系统里某个工具突然报错」这类问题,按固定顺序查,比到处试快得多:



  1. 确认用的是哪个解释器:打印解释器路径与环境前缀,看是不是你以为的那个。

  2. 确认包装到了哪里:看 site-packages 的路径,确认它属于当前环境。

  3. 确认是不是系统环境被污染:回想有没有用 sudo pip 往系统里装过东西;有的话,优先考虑用发行版包管理器把它换成正式包,或者干脆重装那个 python3-xxx 包恢复状态。

  4. 确认命令来源:which 一下那个命令,看它指向哪个目录,别把用户目录里装的工具和系统工具搞混。


常见坑点


❌ 直接 sudo pip install 装包到系统 Python。 ✅ 建虚拟环境再装;系统层面要装就用 apt install python3-xxx。


❌ 想用新版本 Python,就去改系统 python3 的指向。 ✅ 让新旧版本并存,用新版本的完整路径去创建虚拟环境。


❌ 看到 externally-managed-environment 报错就加参数强行安装。 ✅ 这是 PEP 668 的保护机制,改用虚拟环境;强行绕过等于绕过保护。


❌ 在虚拟环境里用裸 pip 命令装包,结果装到了别处。 ✅ 用 python -m pip,确保装包与运行脚本用的是同一个解释器。


❌ 把 .venv 目录整个提交到版本库,或用它来「复制环境」。 ✅ 只提交依赖声明与锁文件,环境由命令重建;环境目录写进忽略规则。


❌ 在 systemd 或 cron 里指望 shell 会先激活虚拟环境。 ✅ 直接写虚拟环境内解释器的完整路径,例如项目目录下的 .venv/bin/python。


❌ 用 update-alternatives --config 选完就不管了,没注意它把链接组切成了手动模式。 ✅ 用 --display 复查模式,需要恢复自动就用 --auto。


❌ 把 apt 装的 python3-xxx 包再用 pip 升级一遍。 ✅ 发行版打包的模块交给 apt 管理,pip 只在虚拟环境里活动,两条线不要交叉。


总结




场景正确做法



日常开发python3 -m venv .venv + python -m pip install

系统层模块apt install python3-xxx

安装被拒绝这是 PEP 668 的保护,改用虚拟环境

要新版本并存安装 + 用完整路径建环境

自动化调用直接指向 .venv/bin/python

切换命令指向慎用 update-alternatives,绝不动系统 python3



Ubuntu 上配置 Python 的全部要点可以压缩成一句话:系统解释器只读不动,你的需求全部放进虚拟环境解决。把「系统 Python」和「开发用 Python」这两个身份彻底分开,绝大多数「装了包却用不了」「系统工具坏掉了」的问题就根本不会发生。




Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐