我是一名在Linux系统上带过几十个新人工程师的运维老手,也给高校开源社团讲过三年Python环境搭建课。每次看到刚接触Ubuntu的同学卡在“明明装了Python却找不到命令”“虚拟环境激活后pip还是装到全局”这类问题上,我就想起自己第一次在服务器上把系统自带的python3.6 pip升级翻车、导致apt包管理器直接罢工的深夜。这篇内容不是教科书式的罗列命令,而是我把过去八年在真实生产环境、教学现场、CI/CD流水线中反复验证过的路径,掰开揉碎讲清楚: 为什么必须用ppa:deadsnakes而不是随便搜个教程抄的源?为什么venv比virtualenv更值得优先用?为什么 source venv/bin/activate 之后还要检查 which python

你不需要是Linux高手,只要能敲几行终端命令,就能照着一步步走通;如果你已经会一点,那文中的版本冲突排查逻辑、PATH变量陷阱、pip源镜像配置细节,可能正是你最近调试失败时缺的那一块拼图。关键词“ubuntu系统入门教程”不是标题党——它真就是从零开始,但绝不停留在“能跑起来”的表面,而是带你理解每一行命令背后系统在做什么。下面我们就从最基础的确认现状开始,不跳步、不省略、不假设你知道任何前置知识。

1. 环境现状诊断与安装策略设计

1.1 先搞清你的Ubuntu到底“自带什么”,别被表象骗了

很多新手一上来就急着装新版本,结果发现 python3 --version 输出3.6.9,心里一慌:“怎么没装上?”其实这是典型误解——Ubuntu系统默认预装的Python3版本,是深度绑定系统管理工具链的,比如 apt update-manager gnome-control-center 这些图形界面和底层服务,全靠这个Python3解释器驱动。你强行卸载或覆盖它,轻则apt报错无法更新软件,重则桌面环境直接崩溃。所以第一步永远不是“装什么”,而是“看清现状”。

我建议你打开终端,依次执行这三行命令,边看边记:

lsb_release -a

这条命令会明确告诉你当前系统版本(比如Ubuntu 18.04.6 LTS),这是后续所有操作的前提。不同LTS版本的软件源策略差异极大:18.04默认只提供3.6,20.04提供3.8,22.04提供3.10,而24.04已默认3.12。如果你用的是20.04或更高版本,其实根本不用额外装3.8——它就在 apt list python3* 里躺着。

第二步:

python3 --version && which python3

注意这里不是 python --version !Ubuntu从16.04起就彻底移除了 python 命令指向Python2的软链接, python 命令默认不存在。 python3 才是正统入口。 which python3 会返回类似 /usr/bin/python3 的路径,这说明你调用的是系统级安装的二进制文件,受 /usr 分区保护,普通用户无权修改。

第三步(关键):

ls /usr/bin/python*

这条命令会列出所有已安装的Python可执行文件。在18.04上,你大概率会看到:

/usr/bin/python3  
/usr/bin/python3.6  
/usr/bin/python3.6m  
/usr/bin/python3m

但不会有 python3.8 ——这说明系统原生确实不带3.8。此时再决定是否要引入第三方源,才叫有的放矢。

提示:不要用 apt search python3 大海捞针。 apt list --installed | grep python3 更精准,它只显示已安装的包,避免被成百上千个无关的python3-*开发包干扰判断。

1.2 为什么选ppa:deadsnakes?不是Ubuntu官方源,但比官方更可靠

当你确认需要3.8且系统没提供时,“去哪装”就成了核心问题。网上常见三种方案:编译源码、用pyenv、加PPA源。我们逐个拆解:

  • 编译源码 :下载tar.gz、 ./configure --enable-optimizations make -j$(nproc) sudo make altinstall 。优点是绝对可控,缺点是耗时(单核编译3.8要20分钟以上)、依赖复杂(需 build-essential , zlib1g-dev , libssl-dev 等12个以上dev包)、易出错( ModuleNotFoundError: No module named '_ctypes' 这种错误新手根本看不懂)。我只在定制嵌入式设备固件时用过,日常开发纯属自找麻烦。

  • pyenv :号称“Python版本管理神器”,通过shim机制拦截命令。但它本质是shell函数+环境变量劫持,对新手极不友好—— pyenv init 输出的那段shell代码要手动加到 .bashrc 里,稍有不慎就让整个终端启动失败;更麻烦的是,它要求用户全程用 pyenv install 3.8.10 而非 apt install ,意味着你要自己处理OpenSSL版本兼容、zlib路径硬编码等问题。我在给大一学生做实训时试过,30人里有7人卡在 pyenv install 无限挂起,最后发现是公司内网DNS污染导致github.com解析失败。

  • ppa:deadsnakes :这才是Ubuntu生态下最务实的选择。它由社区资深维护者维护,所有二进制包都经过Ubuntu官方构建服务器编译,严格遵循Debian打包规范。最关键的是:它 不替换系统Python,只新增可执行文件 。装完后 /usr/bin/python3.8 独立存在,和 /usr/bin/python3.6 完全隔离, apt upgrade 时也不会误删它。而且它提供完整的配套包: python3.8-venv python3.8-dev python3.8-distutils ,一个PPA解决全部依赖。

为什么叫“deadsnakes”?因为Python2.7已于2020年EOL(End of Life),但很多老项目还在用,这个PPA连2.7.18都持续维护——它代表的是一种“向后兼容但不妥协”的工程哲学。我线上跑着的金融风控模型,至今还依赖2.7写的legacy数据清洗脚本,就是靠这个PPA稳稳托住。

注意: ppa:deadsnakes/ppa 仅适用于Ubuntu官方发行版(含Kubuntu/Xubuntu等),不支持WSL1、Docker容器或深度定制版(如Linux Mint)。如果你用的是WSL2,直接 sudo apt update && sudo apt install python3.8 即可,因为WSL2内核已同步Ubuntu 22.04源。

1.3 virtualenv vs python3.x-venv:选哪个?答案取决于你用什么Python

虚拟环境是Python项目的“安全沙箱”,但实现方式有本质区别。很多人以为 virtualenv venv 只是命令不同,其实它们是两代技术:

  • virtualenv(旧时代) :由PyPI上的第三方包提供,需 pip install virtualenv (或 apt install virtualenv )。它通过复制Python解释器二进制文件+符号链接标准库的方式创建隔离环境。优点是兼容性极强(支持Python2.6+),缺点是体积大(每个venv目录约25MB)、启动慢(要加载大量符号链接)、且与系统Python耦合深(一旦系统Python升级,旧venv可能失效)。

  • venv(新时代) :从Python3.3起成为标准库模块(PEP 405),无需额外安装。它采用“硬链接+空目录”策略:只硬链接 /usr/lib/python3.8 下的 .so 文件(节省空间), site-packages 目录完全空白,所有包都通过 pip install 写入。启动快、体积小(新建venv仅3MB)、且与Python版本强绑定—— python3.8 -m venv 创建的环境,只能用3.8解释器运行。

那么该选谁?我的经验是: 只要你的目标Python版本≥3.3,无条件用 venv 。理由很实在:

  1. venv 是CPython官方实现,bug少、文档全、IDE(PyCharm/VSCode)原生支持;
  2. virtualenv 在2023年后已进入维护模式,新特性(如 --system-site-packages 的细粒度控制)不再更新;
  3. 最关键的是—— venv 创建的环境, pip 默认不会继承系统包( --no-site-packages 是默认行为),而 virtualenv 早期版本默认继承,容易引发依赖冲突。

你在正文里看到的两种方法,本质是同一技术的两种调用姿势: virtualenv -p python3.8 venv 是旧包调用新解释器, python3.8 -m venv venv 是新模块直接工作。后者更纯粹、更可控。

2. Python3.8安装全流程实操与原理透析

2.1 添加PPA源的底层机制:不只是“加一行命令”

sudo add-apt-repository ppa:deadsnakes/ppa 这条命令看似简单,背后涉及Ubuntu包管理的完整信任链。我们来拆解它实际做了什么:

首先, add-apt-repository 是一个Python脚本(位于 /usr/bin/add-apt-repository ),它会:

  1. https://launchpad.net/api/1.0/~deadsnakes/+archive/ubuntu/ppa 发起HTTP请求,获取该PPA的元数据;
  2. 下载 https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xXXXXXXXX (PPA维护者的GPG公钥);
  3. 将公钥存入 /etc/apt/trusted.gpg.d/deadsnakes-ubuntu-ppa-focal.gpg (focal是20.04代号,18.04对应bionic);
  4. /etc/apt/sources.list.d/ 下创建 deadsnakes-ubuntu-ppa-bionic.list 文件,内容为:
    deb http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic main
    deb-src http://ppa.launchpad.net/deadsnakes/ppa/ubuntu bionic main
    

提示:如果你的网络环境无法访问launchpad.net(比如某些企业防火墙),可以手动创建list文件。先用浏览器打开 https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa ,在页面底部找到“Technical details about this PPA”,复制对应Ubuntu版本的deb行,粘贴到 /etc/apt/sources.list.d/deadsnakes.list 中,再手动导入公钥: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F23C5A6CF475977595C89F51BA6932366A755776 (这是deadsnakes的当前密钥ID)。

执行完 add-apt-repository 后,必须运行 sudo apt update 。这步常被忽略,但它至关重要: apt update 会下载 http://ppa.launchpad.net/deadsnakes/ppa/ubuntu/dists/bionic/main/binary-amd64/Packages.gz 这个索引文件,里面记录了PPA中所有可用包的名称、版本、依赖关系、SHA256校验值。没有它, apt install python3.8 根本不知道去哪里找安装包。

2.2 安装python3.8及其配套组件的精确命令集

现在进入实操。请严格按顺序执行,每步后观察输出:

# 1. 更新本地包索引(确保获取最新PPA信息)
sudo apt update

# 2. 安装python3.8主程序(核心解释器)
sudo apt install python3.8

# 3. 安装配套开发包(编译C扩展必需,如numpy/scipy)
sudo apt install python3.8-dev

# 4. 安装venv模块(创建虚拟环境的基础)
sudo apt install python3.8-venv

# 5. 安装distutils(旧项目setup.py依赖,避免ImportError)
sudo apt install python3.8-distutils

# 6. 安装pip(Python包管理器,3.8自带pip但需单独安装)
sudo apt install python3.8-pip

注意: python3.8-pip 这个包名容易被忽略。虽然Python3.8源码自带 ensurepip 模块,但Ubuntu打包时默认不启用它,必须显式安装 python3.8-pip 包,否则 python3.8 -m pip 会报错 No module named pip

验证安装是否成功,执行:

python3.8 --version          # 应输出 Python 3.8.10(或你安装的具体版本)
python3.8 -c "import sys; print(sys.path)"  # 查看解释器搜索路径,确认无异常
python3.8 -m pip --version   # 应输出 pip X.X.X from /usr/lib/python3.8/site-packages/pip (python 3.8)

实操心得:如果 python3.8 --version 报错 command not found ,90%是 /usr/bin 不在PATH中。检查 echo $PATH ,正常应包含 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 。若缺失,临时修复: export PATH="/usr/bin:$PATH" ;永久修复:将 export PATH="/usr/bin:$PATH" 加入 ~/.bashrc 末尾,然后 source ~/.bashrc

2.3 版本共存的底层逻辑:为什么 python3.8 python3 能和平共处

很多新手困惑:“装了3.8,那原来的3.6会不会被覆盖?”答案是否定的,原因在于Ubuntu的 多版本并存设计

  • 所有Python3.x版本的可执行文件都放在 /usr/bin/ 下,命名规则为 python3.x (如 python3.6 , python3.8 );
  • /usr/bin/python3 是一个指向 /usr/bin/python3.6 的符号链接( ls -l /usr/bin/python3 可查看);
  • 系统服务(如 /usr/bin/update-manager )在shebang行写的是 #!/usr/bin/python3 ,因此永远调用符号链接指向的版本;
  • 用户手动执行 python3.8 时,直接调用 /usr/bin/python3.8 ,完全绕过符号链接。

你可以用 ls -l /usr/bin/python* 直观看到这个结构:

lrwxrwxrwx 1 root root    9 Apr 10  2020 /usr/bin/python3 -> python3.6
-rwxr-xr-x 1 root root 4.5M Apr 10  2020 /usr/bin/python3.6
-rwxr-xr-x 1 root root 4.7M Oct 15 12:34 /usr/bin/python3.8

这种设计保证了:系统稳定性和用户灵活性同时存在。你既可以用 python3.8 跑新项目,又不用担心 apt upgrade 把系统搞崩。

提示:不要用 sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 1 去切换默认python3。这会破坏系统稳定性, apt 内部脚本可能因调用错误Python版本而失败。需要临时切换时,用 alias python3=python3.8 (仅当前终端有效)更安全。

3. 虚拟环境创建与激活的深度实践

3.1 用 python3.8 -m venv 创建环境的完整流程

这是推荐的标准做法。我们以创建一个名为 myproject 的项目环境为例:

# 1. 创建项目目录(避免在/home下直接建venv,防止权限混乱)
mkdir -p ~/projects/myproject
cd ~/projects/myproject

# 2. 创建虚拟环境(核心命令)
python3.8 -m venv venv

# 3. 激活环境
source venv/bin/activate

# 4. 验证激活状态
which python    # 应输出 ~/projects/myproject/venv/bin/python
python --version # 应输出 Python 3.8.10
pip list         # 应只显示 setuptools, pip, wheel 三个基础包

关键点解析:

  • venv 目录名是约定俗成的,但非强制。你可以叫 env .venv 甚至 py38-env ,只要保持一致即可;
  • source venv/bin/activate 的本质是执行 venv/bin/activate 这个shell脚本,它会:
    1. venv/bin 加入PATH最前面( export PATH="~/projects/myproject/venv/bin:$PATH" );
    2. 设置 VIRTUAL_ENV 环境变量指向venv根目录;
    3. 修改PS1提示符,在前面加上 (venv) 标识;
    4. 定义 deactivate 函数,用于退出环境。

注意: source 是bash/zsh的内置命令, . 是POSIX标准命令,两者等价。在脚本中建议用 . ,交互式终端用 source 更直观。

3.2 激活后必须做的三件事:避免90%的后续坑

刚激活环境,别急着 pip install ,先做这三步检查:

第一,确认pip是否指向venv内的pip:

which pip
# 正确输出:/home/yourname/projects/myproject/venv/bin/pip
# 错误输出:/usr/bin/pip 或 /usr/local/bin/pip(说明激活失败)

第二,升级pip到最新版(venv内pip默认较旧):

pip install --upgrade pip
# 这步很重要!旧版pip(如20.0.2)不支持PEP 517构建,安装modern包(如poetry)会失败

第三,配置国内pip源(加速安装,避免超时):

# 创建pip配置目录
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 = 120
EOF

清华源是目前最稳定的国内镜像, trusted-host 必须显式声明,否则pip会因SSL证书问题拒绝连接。 timeout=120 防止大包(如torch)下载中断。

实操心得:我见过太多人跳过这三步,结果 pip install django 装了半小时失败,最后发现是pip版本太低+源太慢。这三步加起来不到10秒,却能省下你两小时debug时间。

3.3 用 requirements.txt 固化依赖的工业级实践

虚拟环境的价值不仅在于隔离,更在于 可复现 。以下是我在线上部署时强制执行的流程:

# 1. 在激活的venv中安装所需包
pip install django==4.2.7 requests==2.31.0

# 2. 生成精确依赖列表(-e 表示editable mode,-c 表示约束文件)
pip freeze > requirements.txt

# 3. 查看生成的requirements.txt内容
cat requirements.txt
# 输出示例:
# asgiref==3.7.2
# Django==4.2.7
# pytz==2023.3
# sqlparse==0.4.4
# tzdata==2023.3

关键细节:

  • pip freeze 会导出 所有已安装包及其精确版本号 ,包括Django间接依赖的 asgiref sqlparse 等;
  • 不要用 pip list > requirements.txt ,因为它会包含 pkg-resources==0.0.0 这类虚假条目;
  • 生产环境必须用 pip install -r requirements.txt 而非 pip install django ,确保所有机器环境100%一致。

提示:对于大型项目,建议用 pip-tools pip install pip-tools )管理依赖。它支持 requirements.in (顶层依赖)和 requirements.txt (解析后的全量依赖),自动处理版本冲突。但对入门者, pip freeze 已足够。

4. 常见问题与实战排错指南

4.1 经典报错:“Command 'python3.8' not found”

现象 :执行 python3.8 --version 提示 Command 'python3.8' not found, but can be installed with:
原因 :PPA源添加后未执行 sudo apt update ,或 apt update 时网络失败导致索引未下载。
排查步骤

  1. cat /etc/apt/sources.list.d/deadsnakes-ubuntu-ppa-bionic.list 确认文件存在且内容正确;
  2. sudo apt update 2>&1 | grep -i deadsnakes 查看更新日志中是否有 Hit: Get: deadsnakes相关行;
  3. 若无输出,手动测试源可用性: curl -I http://ppa.launchpad.net/deadsnakes/ppa/ubuntu/dists/bionic/ ,应返回HTTP 200。

解决方案

  • 网络问题:换源(如用阿里云镜像) sudo sed -i 's|http://ppa.launchpad.net|https://mirrors.aliyun.com/ubuntu|g' /etc/apt/sources.list.d/deadsnakes-ubuntu-ppa-bionic.list
  • GPG密钥过期: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F23C5A6CF475977595C89F51BA6932366A755776
  • 最后执行 sudo apt update && sudo apt install python3.8

4.2 激活后 pip install 仍装到系统目录

现象 source venv/bin/activate 后, which pip 显示正确路径,但 pip install numpy 后, python -c "import numpy" 未激活环境时也能成功
原因 venv 创建时用了 --system-site-packages 参数(或 virtualenv 默认行为),导致继承了系统 /usr/lib/python3.8/site-packages
验证方法

# 激活环境后
python -c "import site; print(site.getsitepackages())"
# 正常输出应为 ['/home/user/venv/lib/python3.8/site-packages']
# 若包含 '/usr/lib/python3.8/site-packages',则确认被继承

解决方案

  • 彻底重建环境: rm -rf venv && python3.8 -m venv venv (默认不继承);
  • 若必须继承系统包(如已安装CUDA驱动),创建时显式声明: python3.8 -m venv --system-site-packages venv ,但需接受潜在冲突风险。

4.3 “ModuleNotFoundError: No module named 'distutils.util'”

现象 python3.8 -m venv venv 报错,或激活后 pip install 失败。
原因 python3.8-distutils 包未安装。 distutils 是Python标准库模块,但Ubuntu将其拆分为独立deb包,必须手动安装。
解决方案

sudo apt install python3.8-distutils
# 然后重新创建venv
rm -rf venv
python3.8 -m venv venv

4.4 虚拟环境激活后,IDE(PyCharm/VSCode)不识别

现象 :终端里 source venv/bin/activate 一切正常,但在PyCharm中配置Python Interpreter时找不到 venv/bin/python
原因 :IDE启动时未加载用户shell环境(如 .bashrc ),导致 PATH 中无 venv/bin
解决方案

  • PyCharm: File → Settings → Project → Python Interpreter → Add → System Interpreter → 选择venv/bin/python
  • VSCode: Ctrl+Shift+P → Python: Select Interpreter → 找到venv/bin/python
  • 关键 :不要依赖“激活后自动识别”,必须手动指定解释器路径。IDE的Python环境是独立进程,与终端shell无关。

4.5 升级系统Python后,旧venv失效

现象 :Ubuntu从18.04升级到20.04后,原来 python3.6 -m venv venv 创建的环境无法激活,报错 /usr/bin/python3.6: No module named venv
原因 venv 模块随Python版本发布, python3.6-venv 包在20.04中被移除, /usr/lib/python3.6/venv 目录不存在。
解决方案

  • 不推荐 :尝试 sudo apt install python3.6-venv (20.04源中无此包);
  • 推荐 :用新Python重建环境:
    # 备份原requirements
    source old_venv/bin/activate
    pip freeze > requirements_old.txt
    deactivate
    
    # 创建新环境
    python3.8 -m venv new_venv
    source new_venv/bin/activate
    pip install -r requirements_old.txt
    

最后分享一个小技巧:我所有项目的venv目录都统一放在 ~/venvs/ 下,用 mkvenv 函数简化创建:

# 加入 ~/.bashrc
mkvenv() {
  local name=${1:-"venv"}
  mkdir -p ~/venvs/$name
  python3.8 -m venv ~/venvs/$name
  echo "Created ~/venvs/$name. Activate with: source ~/venvs/$name/bin/activate"
}

以后只需 mkvenv myproject ,干净利落。这个习惯让我管理20+个项目环境时,从不担心路径混乱。

更多推荐