Python:入门第一步,解释器、虚拟环境、依赖管理和项目启动方式怎么选
先不讲复杂语法,先做一件实际的事:把一个 Python 小项目从空目录搭到能稳定运行、能装依赖、能跑测试。
第一次卡住,往往不是因为 if 和 for 不会写,而是因为下面这些问题:
- 不知道机器上到底装了几个 Python
python、python3、pip、pip3混着用- 一个项目能跑,换一台机器就不能跑
- 明明安装过依赖,运行时还是报
ModuleNotFoundError - 本地测试能通过,一进 Jenkins 或服务器就失效
这篇文章直接围绕一套最小实践展开,把四件事做完整:
- Python 解释器到底是什么
- 为什么要用虚拟环境
- 依赖管理到底在管什么
- 一个 Python 项目应该怎么启动才算稳
一、这篇文章要解决什么问题
读完这一篇,应该能自己完成这些动作:
- 确认当前机器正在使用哪个 Python 解释器
- 为项目创建独立虚拟环境
- 安装并记录依赖
- 用统一入口启动项目
- 用最小测试验证环境是否可复现
如果这五步能独立做完,后面再学函数、类、pytest、Flask、FastAPI,整个节奏会稳很多。
二、先给一个最小示例
假设现在要新建一个最简单的 Python 项目,只做一件事:读取一个名字,然后打印欢迎语。
目录先不要搞复杂,先长这样:
1 | hello_python/ |
app.py:
1 | def build_message(name: str) -> str: |
先不要急着运行,先完整走一遍项目初始化:
1 | mkdir hello_python |
然后再创建文件。
运行方式:
1 | python app.py |
输出:
1 | hello, python |
这个例子非常小,但已经隐含了四层信息:
python命令背后对应某个解释器- 当前解释器会去找当前环境下的依赖
- 当前目录是项目目录
app.py被当作入口脚本执行
后面所有复杂项目,本质上都没有脱离这几层。
三、直接从零搭一遍
这一节不讲概念,直接按顺序做。
1. 先确认解释器
1 | python3 --version |
可能看到的结果:
1 | Python 3.12.2 |
如果机器上已经激活了虚拟环境,再执行:
1 | python --version |
激活虚拟环境后,更常见的结果是:
1 | Python 3.12.2 |
这两组命令的目的不是背下来,而是先确认“当前到底是谁在执行代码”。
2. 创建项目目录
1 | mkdir demo_project |
3. 创建虚拟环境
1 | python3 -m venv .venv |
4. 激活虚拟环境
1 | source .venv/bin/activate |
激活后,重新确认解释器位置:
1 | which python |
如果输出类似下面这样,说明当前项目已经切到独立环境:
1 | /path/to/demo_project/.venv/bin/python |
5. 安装依赖
1 | python -m pip install pytest |
安装完成后可以顺手确认一次:
1 | python -m pip show pytest |
可能看到的结果:
1 | Name: pytest |
这里最值得看的是 Location。如果它不在 .venv 下面,就说明依赖没有装进当前项目环境。
6. 记录依赖
requirements.txt:
1 | pytest==8.2.0 |
7. 写代码并运行
写完 app.py 后执行:
1 | python app.py |
8. 加一个最小测试
新建 test_app.py:
1 | import pytest |
执行:
1 | pytest -q |
可能看到的结果:
1 | .. [100%] |
如果主程序和测试都能通过,说明这个项目已经不只是“写了点代码”,而是有了最小工程骨架。
四、Python 解释器到底是什么
1. 解释器不是“Python 语言本身”
刚接触这一层时,“Python”很容易被理解成一个模糊概念,实际上至少要区分三件事:
- Python 语言规范
- Python 解释器实现
- 当前机器上实际在执行代码的那个 Python 程序
日常开发里,最常用的是 CPython。当在命令行输入:
1 | python --version |
真正发生的事情是:系统找到一个叫 python 的可执行程序,然后让它去解析并运行代码。
所以“写 Python”并不是抽象地写,而是把代码交给某个具体解释器执行。
2. 为什么机器上可能不止一个解释器
这很正常。一个开发环境里经常同时存在:
- 系统自带 Python
- 手动安装的 Python 3.x
- 某个工具自带的 Python
- 虚拟环境里的 Python
这也是为什么下面这些命令不一定指向同一个东西:
1 | python |
如果这一点没有意识,最容易出现的情况就是:
- 用 A 解释器安装依赖
- 用 B 解释器运行代码
- 最后得到“明明装了依赖但就是找不到模块”的结果
3. 新手最稳的做法是什么
最稳的原则只有一条:
永远把“解释器”和“项目”绑在一起理解,不要把 Python 当成一套全局漂浮的环境。
更具体一点:
- 每个项目都尽量有自己独立的虚拟环境
- 安装依赖时尽量使用当前解释器去调用
pip - 不要依赖“我记得刚才终端里切换过”
更稳的安装方式是:
1 | python -m pip install requests |
而不是直接写:
1 | pip install requests |
前者明确表示:让当前这个 python 对应的环境执行 pip 模块。
后者则可能命中另一个 pip。
这里可以直接做一个对照实验。
错误做法:
1 | pip install requests |
可能出现:
1 | ModuleNotFoundError: No module named 'requests' |
修复做法:
1 | python -m pip install requests |
这样更容易保证“安装依赖”和“执行代码”使用的是同一个解释器。
五、为什么 Python 项目必须尽早使用虚拟环境
1. 虚拟环境到底隔离了什么
第一次看到 venv 时,很容易把它理解成一个“高级工具”。其实它做的事情很朴素:给当前项目准备一套相对独立的 Python 执行环境。
它主要隔离三样东西:
- 当前项目使用的解释器入口
- 当前项目安装的第三方依赖
- 当前项目的脚本执行上下文
这样做的好处非常直接:
- 项目 A 用
requests==2.28 - 项目 B 用
requests==2.31 - 两个项目互不影响
2. 不用虚拟环境会发生什么
假设直接把所有依赖都装到全局环境里,短期看很省事,长期会遇到这些问题:
- 不同项目依赖版本互相覆盖
- 老项目突然因为升级某个库而跑不起来
- 换一台开发机也无法准确复现环境
- 服务器和本地的行为开始不一致
对新手来说,最危险的地方在于:这种问题往往不是立刻发生,而是在项目变多以后慢慢爆出来。
3. 最小可执行做法
创建虚拟环境:
1 | python3 -m venv .venv |
激活虚拟环境:
1 | source .venv/bin/activate |
激活后再看解释器位置:
1 | which python |
这时候通常会指向项目目录下的 .venv/bin/python。
这一步的意义非常大,因为它让“当前项目使用哪个解释器”从模糊状态变成了可验证状态。
如果想再确认一次,可以继续执行:
1 | python -m pip --version |
可能看到:
1 | pip 24.0 from /path/to/demo_project/.venv/lib/python3.12/site-packages/pip (python 3.12) |
只要 pip 路径和 python 路径都落在 .venv 下,这个项目环境通常就是对的。
4. 一个容易忽略的边界
虚拟环境不是万能隔离箱。它解决的是 Python 级别的依赖问题,不解决下面这些问题:
- 操作系统权限
- 系统级动态库
- 数据库服务是否可用
- 外部 API 是否能访问
所以项目能不能运行,不能只盯着 venv。但对 Python 新手来说,先把 Python 自己这一层隔离好,已经能减少大量无效排查。
六、依赖管理到底在管什么
1. 依赖不是“装上就行”
依赖管理如果只停留在下面这种理解:
- 缺库了就
pip install - 能 import 就算结束
这种理解太浅。真正的依赖管理至少包含四件事:
- 这个项目依赖哪些第三方库
- 每个库依赖哪个版本
- 这些依赖如何在其他环境里复现
- 升级依赖时怎么控制风险
换句话说,依赖管理不是“本地能跑”,而是“换一个环境也能按同样方式跑起来”。
2. 为什么版本号重要
第三方库不是静止的。今天安装和下个月安装,很可能就不是同一套代码。
如果完全不管版本,最容易出现:
- 某个 API 已经改了
- 某个默认行为变了
- 旧代码突然出现兼容问题
所以 requirements.txt 的价值,不只是记个名字,而是把当时可运行的依赖集合记录下来。
例如:
1 | requests==2.31.0 |
这意味着:
- 这个项目依赖
requests - 依赖
pytest - 当前验证通过的版本就是这些
3. 新手最容易犯的错误
最常见的错误有三个。
第一种,只在自己机器上 pip install,但不记录依赖。
结果是换机器就无法复现。
第二种,什么都写成“最新版本”。
结果是环境并不稳定,今天能跑明天未必能跑。
第三种,把一堆无关包一起导出,导致 requirements.txt 极度混乱。
结果是文件里根本分不清哪些是真正业务依赖,哪些只是本地调试残留。
4. 实际做法
对刚起步的小项目,先坚持一个简单原则就够了:
- 显式安装需要的依赖
- 把依赖版本写进
requirements.txt - 新环境统一通过文件安装
安装:
1 | python -m pip install requests |
记录:
1 | requests==2.31.0 |
复现:
1 | python -m pip install -r requirements.txt |
这已经比“想到什么装什么”强很多。
实际做法是把下面这组动作连起来:
1 | rm -rf .venv |
如果这组动作能稳定通过,说明依赖记录已经具备基本复现能力。
七、项目启动方式为什么值得单独讲
启动方式最容易先被理解成:
1 | python xxx.py |
这当然是最常见的方式,但项目一复杂,启动方式本身就会影响:
- 导入路径是否正确
- 配置文件从哪里读取
- 相对路径是否稳定
- 测试和正式运行是否一致
1. 脚本启动
最常见:
1 | python app.py |
适合:
- 单文件练习
- 小型脚本
- 初学阶段的最小示例
优点:
- 直观
- 理解成本低
问题:
- 项目一复杂,导入路径容易混乱
- 多入口时不容易统一管理
2. 模块启动
例如:
1 | python -m package_name.app |
适合:
- 已经有包结构的项目
- 需要更稳定导入路径的项目
它的优势在于:让 Python 按模块方式理解项目,而不是仅仅把某个文件当脚本硬跑。
3. 命令行入口启动
再往后一些,会遇到:
- CLI 工具
- 测试 runner
- 自动化任务入口
这时通常会把入口显式整理成:
- 一个
main()函数 - 一个清晰的命令参数层
- 一个稳定的执行入口
这类设计的价值,不在“写法高级”,而在于后面接 Jenkins、定时任务、容器执行时更稳定。
八、一个更像真实项目的最小目录应该长什么样
如果不想一开始就搞得很重,可以先用下面这个骨架:
1 | demo_project/ |
app/service.py:
1 | def build_message(name: str) -> str: |
app/main.py:
1 | from app.service import build_message |
tests/test_service.py:
1 | import pytest |
这个结构虽然小,但已经能直接拿来做三件事:
- 本地运行
- 写最小测试
- 接 Jenkins 或命令行任务
因为它已经开始区分:
- 业务逻辑放哪
- 程序入口放哪
- 测试放哪
- 依赖放哪
九、把这套最小结构真正跑起来
如果按上面的目录落地,更推荐把整个流程走完整一次,而不是只看到目录就停下。
1 | mkdir demo_project |
第一次执行时,更稳一点的顺序是:
1 | mkdir demo_project |
如果是换机器重建环境,再使用:
1 | python -m pip install -r requirements.txt |
运行时重点观察四件事:
python是否来自.venvpytest是否能找到测试from app.service import ...是否导入正常- 失败时是代码问题还是环境问题
如果这里就出现报错,反而是好事,因为刚好可以借这一步把环境理解扎实。
十、为什么这个最小结构比“能跑就行”更重要
因为 Python 项目最容易出现的退化,就是从一个简单脚本开始,慢慢长成一团。
典型过程通常是这样的:
- 一开始只有一个文件
- 后来复制出第二个、第三个
- 又加了一些工具函数
- 又手动改了一些路径
- 又额外装了几个依赖
- 最后项目到底应该怎么启动已经说不清
所以入门阶段就把目录、环境、依赖、入口整理清楚,不是形式主义,而是在防止未来失控。
十一、最常见的错误写法
下面这些写法,几乎每个 Python 新手都会踩一两个。
1. 全局环境直接装所有依赖
问题:
- 项目之间相互污染
- 难以复现
错误写法:
1 | pip install requests pytest flask |
后果:
- 当前项目能跑
- 下一个项目可能被同样一套依赖污染
- 过一段时间很难回忆这些包是给哪个项目装的
实际做法:
- 每个项目单独建
venv
2. 直接用 pip install,但不确认解释器
问题:
- 依赖装进了错误环境
错误写法:
1 | pip install pytest |
可能看到:
1 | No module named pytest |
实际做法:
- 优先用
python -m pip install
3. 项目里只有脚本,没有明确入口
问题:
- 脚本都能跑,但运行方式各不相同
- 后面接自动化流程时容易失控
实际做法:
- 明确一个统一入口,例如
main.py或python -m app.main
例如:
错误写法:
1 | python task1.py |
时间一长,很难分清谁才是正式入口。
修复写法:
1 | python -m app.main |
或者固定:
1 | python main.py |
4. requirements.txt 只是临时导出,不做筛选
问题:
- 文件里充满无关依赖
- 很难判断哪些是真正项目依赖
实际做法:
- 小项目先手工维护核心依赖,保持清晰
例如:
更乱的 requirements.txt:
1 | black==24.4.2 |
如果当前项目只是一个最小脚本工具,这里面就可能混入了不少“本机曾经装过但项目并不依赖”的包。
当前示例项目直接这样写:
1 | pytest==8.2.0 |
十二、怎么测试这一层知识是不是真的掌握了
环境和启动方式不像业务功能那样直观,但依然可以测试。
1. 自测问题
可以让自己回答下面这些问题:
- 当前项目到底用哪个 Python 解释器
- 当前依赖到底装在哪
- 删除虚拟环境后,能不能按文档重新搭起来
- 换一台机器,能不能只靠
requirements.txt跑起来
如果这些问题答不上来,说明还只是“会照着命令敲”,不算真正掌握。
2. 最小验证动作
更推荐做这几步验证:
- 删除旧虚拟环境
- 重新创建
.venv - 按
requirements.txt安装依赖 - 运行主程序
- 运行测试
只要这五步能稳定重复,说明环境骨架基本是对的。
十三、一个真实项目里,这部分通常会在哪出问题
最常见的真实场景不是“本地完全跑不通”,而是下面这些半好半坏的问题:
- 本地能跑,Jenkins 不能跑
- 开发机能跑,服务器不能跑
- 老项目之前能跑,过了一段时间突然不能跑
- 同一项目在不同开发环境里跑出来的结果不一致
这类问题往往不是业务逻辑问题,而是下面这些基础环节出了偏差:
- 解释器版本不一致
- 依赖版本漂移
- 启动方式不统一
- 项目目录和导入路径设计不稳
所以这篇文章看起来像“入门篇”,其实它解决的是 Python 工程的底盘问题。
十四、一个实际排错场景:为什么本地能跑,Jenkins 一跑就报错
这类问题非常典型。
场景通常是这样:
- 本地 IDE 已经自动选中了某个虚拟环境
- 开发者直接点运行,一切正常
- 代码提交后,Jenkins 在干净环境重新执行
- 结果报
ModuleNotFoundError或依赖版本错误
排查顺序更推荐这样走:
- 先确认 Jenkins 使用的解释器版本
- 再确认依赖是否按同一份
requirements.txt安装 - 再确认启动命令是不是和本地一致
- 最后再看代码本身
这类场景里如果一看到报错就直接改代码,排查往往会被带偏。根因常常不在代码,而在运行入口和环境没有对齐。
例如,Jenkins 日志里可能看到:
1 | ModuleNotFoundError: No module named 'pytest' |
这时更合适的动作不是先改测试代码,而是先补下面这些输出:
1 | python --version |
如果要把这个排查过程做得更像工程实践,更推荐在 Jenkins 任务里先显式打印这些信息:
1 | python --version |
这样至少能先回答两个关键问题:
- 当前到底用了哪个解释器
- 当前环境到底装了哪些包
比起直接猜“是不是 pytest 版本不对”,这种排查更稳。
如果确认是环境问题,修复动作通常就是回到这组命令:
1 | python3 -m venv .venv |
十五、一个实际练习
可以按下面这个练习自己完整做一遍。
目标:做一个命令行小工具,输入名字,输出欢迎语,并加上测试。
要求:
- 创建独立虚拟环境
- 安装
pytest - 写
build_message()函数 - 写
main()作为统一入口 - 写至少 2 个测试
- 删除
.venv后重新搭一遍
如果这 6 步能独立完成,说明这一篇最核心的实践已经真正掌握。
十六、这篇文章学完以后,下一步应该补什么
如果这篇文章已经理解,下一步最适合继续补的是:
- Python 基础语法怎么学才不会停留在玩具代码
- 列表、字典、集合这些内置容器为什么不只是“会用”
- 函数参数、可变对象、作用域为什么总是容易出错
原因很简单:环境和入口解决的是“代码怎么稳定跑起来”,而后面这些内容解决的是“代码为什么这样运行”。
十七、结语
这一篇最重要的,不是记住多少概念,而是亲手把下面这套动作做顺:
- 建项目
- 建虚拟环境
- 安装依赖
- 运行程序
- 跑测试
- 删除环境再重建
只要这套动作能稳定重复,Python 的入门就不是“会写几行代码”,而是真正开始具备工程起点了。