Ubuntu 20.04 搭建 Python 3.9 开发环境:PPA+venv+pipx 实战指南

📅 2026/6/22 11:30:36
Ubuntu 20.04 搭建 Python 3.9 开发环境:PPA+venv+pipx 实战指南
1. 项目概述为什么在 Ubuntu 20.04 上亲手搭 Python 3 开发环境比点几下安装包重要十倍Python 3、Ubuntu 20.04、ambiente de programação——这三个词凑在一起不是一句简单的“装个Python”而是一道分水岭。我带过二十多个刚从学校出来的实习生八成人在公司配好环境后第一周都在反复重装系统有人用apt install python3装完发现 pip 没权限pip install numpy报错 PermissionDenied有人图省事直接sudo pip install结果三天后import torch失败查日志发现/usr/local/lib/python3.8/dist-packages/下混着 Python 3.8 和 3.9 的包版本锁死还有人照着某篇“三分钟搞定”的教程执行curl https://bootstrap.pypa.io/get-pip.py | sudo python3结果 pip 自动升级到 24.x把公司内部私有源的认证协议给干掉了连不上内网镜像。这些都不是玄学是 Ubuntu 20.04 这个 LTS 版本里Python 3.8 系统自带、apt 包管理器与用户级 pip 生态之间那层薄如蝉翼却极易撕裂的信任关系。Ubuntu 20.04 的默认 Python 3 是 3.8.10它被系统深度绑定——apt update、unattended-upgrades、甚至gnome-control-center的后台服务都依赖这个解释器。你不能删也不该动。但开发需要的是 Python 3.9、3.10 或 3.11要装 PyTorch、TensorFlow、FastAPI要隔离项目依赖要随时回滚。这时候“instalar”和“configurar”就不再是两个动词而是两套逻辑前者是让 Python 解释器跑起来后者是让整个开发流稳定、可复现、可协作。我见过最惨的一次是同事在服务器上用apt install python3-dev顺手装了python3.8-venv结果python3 -m venv myenv创建的虚拟环境里pip list显示setuptools是 50.3.2但pip install --upgrade pip升级后pip install -r requirements.txt直接卡死在Building wheel for cryptography查了六小时才发现是python3.8-dev带的libssl-dev版本太老和新版cryptography编译不兼容。这种问题任何图形化安装器都救不了你。所以这篇指南不叫“Ubuntu 20.04 安装 Python 教程”它叫“Python 3 开发环境基建手册”。它面向三类人刚转 Linux 的 Python 新手需要避开所有sudo pip陷阱数据科学入门者准备跑通conda create -n pytorch_env python3.9这条命令背后的完整链路还有运维或 DevOps 工程师要批量部署上百台 Ubuntu 20.04 机器确保每台的python --version和pip --version输出都精确到小数点后两位且虚拟环境创建成功率 100%。我们不用 Snap、不碰 Flatpak、不推荐pyenv全局管理它在 CI/CD 流水线里容易出时序问题只用 Ubuntu 20.04 官方仓库 deadsnakesPPA venv标准库这三样东西把事情做扎实。接下来每一行命令我都告诉你它改了哪个文件、为什么不能少、如果跳过会埋下什么雷——因为真正的 ambiente de programação从来不是“能跑就行”而是“下次重启、换机器、加新人还能原样复现”。2. 环境设计底层逻辑为什么放弃 apt、pyenv、conda而选择“PPA venv pipx”铁三角2.1 Ubuntu 20.04 的 Python 生态困局系统 Python 不是你的开发 PythonUbuntu 20.04 的/usr/bin/python3指向/usr/bin/python3.8这是铁律。apt list --installed | grep python3会列出三十多个包python3,python3-minimal,python3-distutils,python3-lib2to3,python3-venv……它们共同构成一个精密咬合的齿轮组。你执行sudo apt install python3-pip它会自动拉取python3-setuptools和python3-wheel版本号被严格锁定在python3.8对应的 ABI 兼容范围内。这不是缺陷是设计哲学系统稳定性优先。但开发恰恰需要打破这种稳定。比如你要用black23.10.1它要求click8.0而 Ubuntu 20.04 仓库里的python3-click是 7.0-3ubuntu1apt install python3-click会拒绝降级pip install click又可能污染系统 site-packages。这就是“系统 Python”和“开发 Python”的根本冲突——前者是操作系统的一部分后者是你代码的运行载体。提示永远不要执行sudo rm /usr/bin/python3或sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 1。我亲眼见过一位同事这么干结果apt upgrade失败dpkg报错python3: dependency problems - leaving unconfigured最后重装了整个系统。2.2 为什么不用 apt 安装高版本 Python——版本碎片与 ABI 风险Ubuntu 官方仓库只提供 Python 3.8。有人会说“那我编译安装 Python 3.10 呗”可以但代价巨大。手动编译需要build-essential,zlib1g-dev,libncurses5-dev,libgdbm-dev,libnss3-dev,libssl-dev,libreadline-dev,libsqlite3-dev这八个开发包缺一个./configure就报错no module named _ssl或readline not found。更麻烦的是 ABIApplication Binary Interface兼容性。Python 扩展模块如numpy,pandas通过.so文件调用 C 库它们编译时链接的libpython3.8.so地址和你编译的libpython3.10.so地址完全不同。当你pip install numpy时pip 会去 PyPI 下载预编译的numpy-1.24.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl这个 wheel 里硬编码了libpython3.10.so.1.0的路径。但如果你的系统没有这个库或者路径不对import numpy就会 Segmentation Fault。我试过三次手动编译 Python 3.10每次都要重新编译openssl和zlib并用LD_LIBRARY_PATH临时指定路径CI 流水线里根本不可控。2.3 为什么不用 pyenv——全局切换在生产环境是定时炸弹pyenv是神器但它解决的是“多版本共存”问题不是“环境隔离”问题。pyenv global 3.10.12会让所有 shell 会话默认用 Python 3.10这在个人笔记本上很爽但在服务器上就是灾难。systemd服务、cron任务、jenkinsagent 启动脚本都可能隐式调用/usr/bin/python3一旦pyenv的 shims 被加载它们就可能意外使用 3.10而某个关键服务只兼容 3.8。更致命的是pyenv的初始化方式它要求你在~/.bashrc里加export PYENV_ROOT$HOME/.pyenv和command -v pyenv /dev/null || export PATH$PYENV_ROOT/bin:$PATH然后eval $(pyenv init -)。这个init -输出的是一段 Bash 函数它会劫持python命令。但在非交互式 shell如ssh userhost python --version里.bashrc默认不加载pyenv就失效了。我维护的一个监控脚本就因为pyenv在 cron 环境里没生效python3调用的是系统 3.8而脚本里用了match-case语法3.10 特性直接SyntaxError退出告警邮件堆了两百封。2.4 为什么不用 conda——重量级方案在轻量需求里是杀鸡用牛刀conda create -n pytorch_env python3.9这条命令确实优雅但它背后是 Anaconda Distribution 的完整生态conda自己的包管理器、独立的lib目录、conda-forge镜像源、以及一套和 pip 完全不同的依赖解析引擎。在 Ubuntu 20.04 上conda安装包体积超过 600MBbase环境初始化要十分钟。更关键的是conda的python3.9并不是标准 CPython它是 Miniconda 编译的定制版sysconfig.get_config_var(LIBDIR)返回的路径和系统 Python 完全不同。当你需要混合使用pip install比如公司私有包只提供 wheel和conda install时pip安装的包会被放到conda环境的site-packages里但conda list看不到conda env export也导不出环境无法复现。我参与过一个医疗影像项目算法团队用 conda后端团队用 pip最后部署时发现torchvision的 CUDA 版本不一致GPU 利用率卡在 10%查了两天才发现是 conda 安装的pytorch和 pip 安装的torchvision链接了不同的libcudnn.so。2.5 我们的选择deadsnakes PPA venv pipx —— 精准、轻量、可审计最终方案是三件套deadsnakes PPA一个由社区维护的、专为 Ubuntu LTS 版本提供新 Python 版本的官方认可源。它提供的python3.9,python3.10,python3.11包全部经过apt签名验证ABI 与系统完全兼容安装后python3.9命令直接可用/usr/lib/python3.9/config-3.9-x86_64-linux-gnu/下的Makefile和pyconfig.h都是标准 CPython 配置。venvPython 3.3 内置的标准库模块python3.9 -m venv myenv创建的虚拟环境完全隔离sys.pathpip install只影响myenv/lib/python3.9/site-packages/activate后which python指向myenv/bin/python绝对干净。pipx专为安装“命令行应用”设计的工具比如black,pre-commit,poetry。它把每个应用安装到独立的虚拟环境中pipx install black后black命令全局可用但它的依赖和你的项目环境零耦合。pipx list一目了然pipx uninstall black一键清理比sudo pip install安全一百倍。这个组合的优势在于它不挑战 Ubuntu 的包管理哲学而是顺应它它不引入新包管理器只用apt和pip这两个最成熟的工具它每一个环节都可审计、可复现、可写进 Ansible Playbook。下面我们就从零开始一行命令、一个参数地拆解。3. 实操全流程从裸机 Ubuntu 20.04 到可交付的 Python 3.9 开发环境3.1 基础系统检查与更新别跳过这三步否则后面全是坑在任何操作前先确认你的 Ubuntu 20.04 是干净的。打开终端执行lsb_release -a输出必须包含Distributor ID: Ubuntu和Description: Ubuntu 20.04.6 LTS或 20.04.1 到 20.04.6 中的任意一个。如果不是 20.04.x请停止操作——这个指南不适用于 22.04 或 18.04。接着检查系统更新状态sudo apt update sudo apt list --upgradable如果--upgradable列出大量包尤其是python3-*相关的如python3-distutils,python3-lib2to3必须先升级sudo apt upgrade -y sudo reboot重启后再次运行lsb_release -a确认内核版本是5.4.0-xx-generic20.04 标准内核。这一步不能省因为deadsnakesPPA 的包依赖特定版本的libc6和libssl1.1如果系统没打满补丁apt install python3.9会报unmet dependencies。我遇到过最诡异的一次是某台云服务器的apt upgrade卡在grub-pc配置上没手动确认导致后续所有apt操作都失败apt --fix-broken install也无效最后只能重装。注意sudo apt upgrade和sudo apt full-upgrade有本质区别。前者只升级现有包不删除或安装新包后者可能移除旧包、安装新包风险更高。我们只用upgrade因为它足够安全且能解决 99% 的依赖问题。3.2 添加 deadsnakes PPA 并安装 Python 3.9四行命令零误差PPAPersonal Package Archive是 Ubuntu 的官方扩展机制。deadsnakes是最老牌、最稳定的 Python 版本 PPA地址是ppa:deadsnakes/ppa。添加步骤如下sudo apt install -y software-properties-common sudo add-apt-repository ppa:deadsnakes/ppa -y sudo apt update sudo apt install -y python3.9 python3.9-venv python3.9-dev逐行解释software-properties-common提供add-apt-repository命令Ubuntu 20.04 默认不装必须先装。add-apt-repository ppa:deadsnakes/ppa -y-y参数自动确认避免交互式提示卡住。这条命令会在/etc/apt/sources.list.d/deadsnakes-ubuntu-ppa-focal.list创建源文件并自动导入 GPG 密钥。apt update刷新包索引让apt知道python3.9这个包存在。apt install python3.9 python3.9-venv python3.9-dev三个包缺一不可。python3.9是解释器本体python3.9-venv提供pyvenv脚本和venv模块支持python3.9-dev包含Python.h头文件和libpython3.9.a静态库是后续编译cryptography、numpy等 C 扩展的必需品。安装完成后验证python3.9 --version python3.9 -c import sys; print(sys.path)第一行应输出Python 3.9.18或当前最新 patch 版本第二行会显示一个很长的路径列表其中第一个是空字符串表示当前目录第二个是/usr/lib/python3.9第三个是/usr/lib/python3.9/lib-dynload——这证明python3.9是标准安装sys.path结构和系统 Python 一致。实操心得如果apt install python3.9报错E: Unable to locate package python3.999% 是apt update没成功。执行cat /etc/apt/sources.list.d/deadsnakes-ubuntu-ppa-focal.list确认内容是deb http://ppa.launchpad.net/deadsnakes/ppa/ubuntu focal main。如果不是focalUbuntu 20.04 代号而是jammy22.04或bionic18.04说明你加错了 PPA用sudo add-apt-repository --remove ppa:deadsnakes/ppa移除后重试。3.3 配置 pip 全局源与信任提速 5 倍绕过证书墙Ubuntu 20.04 的pip默认走https://pypi.org/simple/国内访问慢如蜗牛且某些企业网络会拦截 TLS 握手。我们必须配置国内镜像源。但注意不能简单pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple/因为pip配置文件位置因用户而异且sudo pip和普通用户pip配置不共享。最佳实践是创建pip.conf全局配置mkdir -p ~/.pip cat ~/.pip/pip.conf EOF [global] index-url https://pypi.tuna.tsinghua.edu.cn/simple/ trusted-host pypi.tuna.tsinghua.edu.cn timeout 60 retries 5 [install] ignore-installed setuptools EOF这个配置文件做了四件事index-url指向清华 TUNA 镜像下载速度提升 5 倍以上。trusted-host告诉 pip 这个域名是可信的绕过 SSL 证书验证清华镜像用的是 Lets Encrypt 证书但某些老旧系统 OpenSSL 版本太低会报CERTIFICATE_VERIFY_FAILED。timeout和retries防止网络抖动导致安装中断。ignore-installed setuptools这是关键Ubuntu 20.04 的python3.9-venv包里预装了setuptools44.0.0但很多新包如poetry要求setuptools50。如果不加这行pip install poetry会报setuptools 44.0.0 is incompatible然后卡死。加上后pip 会忽略已安装的旧版强制安装新版。验证配置是否生效python3.9 -m pip config list python3.9 -m pip install --upgrade pip第二行会升级 pip 到最新版目前是 23.3.1耗时约 30 秒。升级后python3.9 -m pip --version应输出pip 23.3.1 from /home/username/.local/lib/python3.9/site-packages/pip (python 3.9)。注意路径是~/.local/不是/usr/这证明 pip 是用户级安装不会污染系统。3.4 创建并激活项目虚拟环境一个命令彻底隔离现在我们有了python3.9有了加速的pip下一步是创建开发环境。假设你的项目叫myproject在~/projects/目录下mkdir -p ~/projects/myproject cd ~/projects/myproject python3.9 -m venv venv source venv/bin/activatepython3.9 -m venv venv这条命令会在当前目录创建venv/文件夹venv/bin/下生成python,pip,activate三个脚本venv/lib/python3.9/site-packages/是空的只有pip和setuptools的初始 wheelvenv/pyvenv.cfg记录了home /usr/bin指向系统python3.9解释器include-system-site-packages false确保隔离。source venv/bin/activate后你的 shell 提示符会变成(venv) usernamehost:~/projects/myproject$此时which python输出/home/username/projects/myproject/venv/bin/pythonpython --version是3.9.18pip list只显示pip,setuptools,wheel三个包。这才是干净的起点。注意永远不要用sudo python3.9 -m venv venv。sudo会把venv/所有文件属主设为root你后续pip install会报Permission denied。如果误操作了用sudo chown -R $USER:$USER venv/修复。3.5 安装核心开发工具pipx 管理 CLIvenv 管理项目依赖开发环境的核心是两类工具一类是全局命令行工具如black,pre-commit,poetry它们应该和项目无关另一类是项目依赖如flask,requests,numpy它们必须严格绑定到venv。我们用pipx管理前者pip管理后者。先安装pipxpython3.9 -m pip install --user pipx python3.9 -m pipx ensurepath--user参数确保pipx安装到~/.local/bin/ensurepath会修改~/.bashrc添加export PATH$HOME/.local/bin:$PATH。执行后必须新开一个终端或运行source ~/.bashrc否则pipx命令找不到。然后安装常用 CLI 工具pipx install black pipx install pre-commit pipx install poetry pipx install jupyterpipx install的原理是为每个工具创建一个独立的虚拟环境如~/.local/pipx/venvs/black/然后把black命令软链接到~/.local/bin/black。这样black --version会调用它自己的venv和你的myproject/venv完全无关。pipx list会清晰列出所有已安装工具及其 Python 版本。对于项目依赖回到myproject目录激活venv后安装cd ~/projects/myproject source venv/bin/activate pip install flask requests numpypip list现在会显示flask,requests,numpy但pipx list里看不到它们——职责分明。3.6 验证环境完整性五项测试一个都不能漏一个可靠的 ambiente de programação 必须通过以下测试Python 版本测试python --version # 应输出 3.9.18pip 源测试pip config list # 应显示清华源 pip install -q requests python -c import requests; print(requests.__version__) # 应输出 2.31.x虚拟环境隔离测试deactivate pip list | grep flask # 应无输出 source venv/bin/activate pip list | grep flask # 应输出 flaskC 扩展编译测试验证python3.9-dev是否生效pip install -q cryptography python -c from cryptography.hazmat.primitives import hashes; print(OK)CLI 工具独立性测试which black # 应输出 /home/username/.local/bin/black deactivate black --version # 仍应正常工作全部通过说明环境搭建成功。你可以开始写app.py了。4. 常见问题与排查技巧实录那些让我熬过三个通宵的坑4.1 问题python3.9 -m venv venv报错ModuleNotFoundError: No module named venv现象执行python3.9 -m venv venv时终端输出ModuleNotFoundError: No module named venv但python3.9 --version正常。原因你只安装了python3.9没装python3.9-venv。venv模块不是 Python 解释器内置的它是一个独立的 Debian 包必须显式安装。排查dpkg -l | grep python3.9-venv如果无输出说明没装。解决sudo apt install -y python3.9-venv实操心得python3.9-venv包很小100KB但它依赖python3.9和python3.9-distutils。如果apt install python3.9-venv报unmet dependencies先运行sudo apt --fix-broken install再重试。4.2 问题pip install时卡在Building wheel for cryptographyCPU 占用 100%现象pip install cryptography或pip install numpy时终端长时间无响应htop显示gcc进程 CPU 占满。原因cryptography1.9 版本默认启用 Rust 编译器rustc而 Ubuntu 20.04 默认没有rustc。pip 会尝试用gcc编译但cryptography的 C 代码量极大编译时间超长且容易内存溢出。排查python3.9 -m pip install --no-binarycryptography cryptography如果这行命令也卡住确认是编译问题。解决推荐安装预编译 wheel跳过编译python3.9 -m pip install --only-binaryall cryptography或者安装 Rust 工具链如果必须源码编译curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y source $HOME/.cargo/env python3.9 -m pip install cryptography注意--only-binaryall会强制 pip 只下载 wheel不编译任何东西。对于numpy,pandas,scipy等科学计算包这是最稳妥的选择因为它们的 wheel 都经过充分测试。4.3 问题jupyter notebook启动后浏览器打不开提示Connection failed现象执行jupyter notebook终端显示The Jupyter Notebook is running at: http://localhost:8888/但浏览器访问http://localhost:8888显示This site can’t be reached。原因Jupyter 默认绑定127.0.0.1本地回环如果你在远程服务器如云主机上运行localhost指向服务器自身不是你的本地电脑。你需要让 Jupyter 绑定到0.0.0.0。排查netstat -tuln | grep :8888如果输出是127.0.0.1:8888说明绑定错误。解决jupyter notebook --ip0.0.0.0 --port8888 --no-browser --allow-root--allow-root是必须的因为jupyter默认禁止 root 用户启动而服务器上常用 root。安全提示--ip0.0.0.0会让 Jupyter 暴露在公网务必配合防火墙。在云服务器上先运行sudo ufw allow 8888再启动 Jupyter。本地开发机无需此步。4.4 问题pipx install poetry后poetry init报错No module named distutils.util现象poetry init时终端输出ModuleNotFoundError: No module named distutils.util。原因poetry依赖distutils而 Ubuntu 20.04 的python3.9-distutils包名是python3.9-distutils但pipx创建的虚拟环境里distutils模块路径没被正确识别。排查pipx run --verbose poetry --version看详细日志里distutils的 import 路径。解决根治安装python3.9-distutilssudo apt install -y python3.9-distutils然后重新安装poetrypipx uninstall poetry pipx install poetry4.5 问题conda create -n pytorch_env python3.9成功但python -c import torch报错libtorch_python.so: cannot open shared object file现象这是标题里提到的热词虽然我们不主推 conda但很多人会混用。conda activate pytorch_env后import torch失败ldd $(python -c import torch; print(torch.__file__)) | grep torch显示libtorch_python.so not found。原因PyTorch 的 conda 包依赖libglib-2.0.so.0而 Ubuntu 20.04 的libglib2.0-0版本是 2.64conda 的pytorch包编译时链接的是libglib-2.0.so.0的旧符号。系统libglib2.0-0更新后符号不匹配。排查apt list --installed | grep libglib2.0如果版本是2.64.6-1~ubuntu20.04.7或更高就是此问题。解决conda install -c conda-forge glib2.64.6或者更彻底的方案卸载 conda回归pip安装 PyTorchpip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118cu118表示 CUDA 11.8根据你的 GPU 驱动选择常见问题速查表问题现象根本原因一行解决命令apt install python3.9报E: Unable to locate packageapt update未执行或 PPA 添加失败sudo add-apt-repository --remove ppa:deadsnakes/ppa sudo add-apt-repository ppa:deadsnakes/ppa sudo apt updatepip install速度极慢pip 源未配置或trusted-host缺失echo -e [global]\nindex-url https://pypi.tuna.tsinghua.edu.cn/simple/\ntrusted-host pypi.tuna.tsinghua.edu.cn ~/.pip/pip.confjupyter notebook无法访问绑定 IP 错误或端口被防火墙拦截jupyter notebook --ip0.0.0.0 --port8888 --no-browser --allow-root sudo ufw allow 8888poetry命令找不到distutilspython3.9-distutils未安装sudo apt install -y python3.9-distutils pipx reinstall poetrycryptography安装卡死缺少 Rust 或编译资源不足python3.9 -m pip install --only-binaryall cryptography5. 进阶配置与团队协作让环境从“能用”到“可交付”5.1 生成可复现的环境快照requirements.txt 与 pyproject.toml 的取舍一个项目要交付给同事或部署到服务器光有代码不够必须有环境定义。Python 社区有两种主流方案requirements.txt传统和pyproject.toml现代。我的建议是新项目用pyproject.toml老项目用requirements.txt。requirements.txt的生成很简单pip freeze requirements.txt但它有个致命缺陷pip freeze会导出venv里所有包包括pip,setuptools,wheel而这些不是你的项目依赖。更糟的是它不区分直接依赖和间接依赖transitive dependencyrequests依赖urllib3,chardet,idna,certifipip freeze全部列出来版本锁死导致pip install -r requirements.txt时urllib3的版本可能和requests的期望不兼容。pyproject.toml是 PEP 518 标准用poetry或pip-tools管理。以poetry为例