Python:入门第一步,解释器、虚拟环境、依赖管理和项目启动方式怎么选

先不讲复杂语法,先做一件实际的事:把一个 Python 小项目从空目录搭到能稳定运行、能装依赖、能跑测试。

第一次卡住,往往不是因为 iffor 不会写,而是因为下面这些问题:

  • 不知道机器上到底装了几个 Python
  • pythonpython3pippip3 混着用
  • 一个项目能跑,换一台机器就不能跑
  • 明明安装过依赖,运行时还是报 ModuleNotFoundError
  • 本地测试能通过,一进 Jenkins 或服务器就失效

这篇文章直接围绕一套最小实践展开,把四件事做完整:

  1. Python 解释器到底是什么
  2. 为什么要用虚拟环境
  3. 依赖管理到底在管什么
  4. 一个 Python 项目应该怎么启动才算稳

一、这篇文章要解决什么问题

读完这一篇,应该能自己完成这些动作:

  • 确认当前机器正在使用哪个 Python 解释器
  • 为项目创建独立虚拟环境
  • 安装并记录依赖
  • 用统一入口启动项目
  • 用最小测试验证环境是否可复现

如果这五步能独立做完,后面再学函数、类、pytest、Flask、FastAPI,整个节奏会稳很多。

二、先给一个最小示例

假设现在要新建一个最简单的 Python 项目,只做一件事:读取一个名字,然后打印欢迎语。

目录先不要搞复杂,先长这样:

1
2
3
4
hello_python/
├── app.py
├── requirements.txt
└── .venv/

app.py

1
2
3
4
5
6
7
8
def build_message(name: str) -> str:
if not name.strip():
raise ValueError("name can not be empty")
return f"hello, {name}"


if __name__ == "__main__":
print(build_message("python"))

先不要急着运行,先完整走一遍项目初始化:

1
2
3
4
5
mkdir hello_python
cd hello_python
python3 -m venv .venv
source .venv/bin/activate
python -m pip install pytest

然后再创建文件。

运行方式:

1
python app.py

输出:

1
hello, python

这个例子非常小,但已经隐含了四层信息:

  • python 命令背后对应某个解释器
  • 当前解释器会去找当前环境下的依赖
  • 当前目录是项目目录
  • app.py 被当作入口脚本执行

后面所有复杂项目,本质上都没有脱离这几层。

三、直接从零搭一遍

这一节不讲概念,直接按顺序做。

1. 先确认解释器

1
2
python3 --version
which python3

可能看到的结果:

1
2
Python 3.12.2
/usr/local/bin/python3

如果机器上已经激活了虚拟环境,再执行:

1
2
python --version
which python

激活虚拟环境后,更常见的结果是:

1
2
Python 3.12.2
/path/to/demo_project/.venv/bin/python

这两组命令的目的不是背下来,而是先确认“当前到底是谁在执行代码”。

2. 创建项目目录

1
2
mkdir demo_project
cd 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
2
3
Name: pytest
Version: 8.2.0
Location: /path/to/demo_project/.venv/lib/python3.12/site-packages

这里最值得看的是 Location。如果它不在 .venv 下面,就说明依赖没有装进当前项目环境。

6. 记录依赖

requirements.txt

1
pytest==8.2.0

7. 写代码并运行

写完 app.py 后执行:

1
python app.py

8. 加一个最小测试

新建 test_app.py

1
2
3
4
5
6
7
8
9
10
11
12
import pytest

from app import build_message


def test_build_message_success():
assert build_message("python") == "hello, python"


def test_build_message_empty():
with pytest.raises(ValueError):
build_message(" ")

执行:

1
pytest -q

可能看到的结果:

1
2
..                                                                   [100%]
2 passed in 0.02s

如果主程序和测试都能通过,说明这个项目已经不只是“写了点代码”,而是有了最小工程骨架。

四、Python 解释器到底是什么

1. 解释器不是“Python 语言本身”

刚接触这一层时,“Python”很容易被理解成一个模糊概念,实际上至少要区分三件事:

  • Python 语言规范
  • Python 解释器实现
  • 当前机器上实际在执行代码的那个 Python 程序

日常开发里,最常用的是 CPython。当在命令行输入:

1
python --version

真正发生的事情是:系统找到一个叫 python 的可执行程序,然后让它去解析并运行代码。

所以“写 Python”并不是抽象地写,而是把代码交给某个具体解释器执行。

2. 为什么机器上可能不止一个解释器

这很正常。一个开发环境里经常同时存在:

  • 系统自带 Python
  • 手动安装的 Python 3.x
  • 某个工具自带的 Python
  • 虚拟环境里的 Python

这也是为什么下面这些命令不一定指向同一个东西:

1
2
3
4
python
python3
pip
pip3

如果这一点没有意识,最容易出现的情况就是:

  • 用 A 解释器安装依赖
  • 用 B 解释器运行代码
  • 最后得到“明明装了依赖但就是找不到模块”的结果

3. 新手最稳的做法是什么

最稳的原则只有一条:

永远把“解释器”和“项目”绑在一起理解,不要把 Python 当成一套全局漂浮的环境。

更具体一点:

  • 每个项目都尽量有自己独立的虚拟环境
  • 安装依赖时尽量使用当前解释器去调用 pip
  • 不要依赖“我记得刚才终端里切换过”

更稳的安装方式是:

1
python -m pip install requests

而不是直接写:

1
pip install requests

前者明确表示:让当前这个 python 对应的环境执行 pip 模块。
后者则可能命中另一个 pip

这里可以直接做一个对照实验。

错误做法:

1
2
pip install requests
python app.py

可能出现:

1
ModuleNotFoundError: No module named 'requests'

修复做法:

1
2
python -m pip install requests
python app.py

这样更容易保证“安装依赖”和“执行代码”使用的是同一个解释器。

五、为什么 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 就算结束

这种理解太浅。真正的依赖管理至少包含四件事:

  1. 这个项目依赖哪些第三方库
  2. 每个库依赖哪个版本
  3. 这些依赖如何在其他环境里复现
  4. 升级依赖时怎么控制风险

换句话说,依赖管理不是“本地能跑”,而是“换一个环境也能按同样方式跑起来”。

2. 为什么版本号重要

第三方库不是静止的。今天安装和下个月安装,很可能就不是同一套代码。

如果完全不管版本,最容易出现:

  • 某个 API 已经改了
  • 某个默认行为变了
  • 旧代码突然出现兼容问题

所以 requirements.txt 的价值,不只是记个名字,而是把当时可运行的依赖集合记录下来。

例如:

1
2
requests==2.31.0
pytest==8.2.0

这意味着:

  • 这个项目依赖 requests
  • 依赖 pytest
  • 当前验证通过的版本就是这些

3. 新手最容易犯的错误

最常见的错误有三个。

第一种,只在自己机器上 pip install,但不记录依赖。
结果是换机器就无法复现。

第二种,什么都写成“最新版本”。
结果是环境并不稳定,今天能跑明天未必能跑。

第三种,把一堆无关包一起导出,导致 requirements.txt 极度混乱。
结果是文件里根本分不清哪些是真正业务依赖,哪些只是本地调试残留。

4. 实际做法

对刚起步的小项目,先坚持一个简单原则就够了:

  • 显式安装需要的依赖
  • 把依赖版本写进 requirements.txt
  • 新环境统一通过文件安装

安装:

1
2
python -m pip install requests
python -m pip install pytest

记录:

1
2
requests==2.31.0
pytest==8.2.0

复现:

1
python -m pip install -r requirements.txt

这已经比“想到什么装什么”强很多。

实际做法是把下面这组动作连起来:

1
2
3
4
5
rm -rf .venv
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
pytest -q

如果这组动作能稳定通过,说明依赖记录已经具备基本复现能力。

七、项目启动方式为什么值得单独讲

启动方式最容易先被理解成:

1
python xxx.py

这当然是最常见的方式,但项目一复杂,启动方式本身就会影响:

  • 导入路径是否正确
  • 配置文件从哪里读取
  • 相对路径是否稳定
  • 测试和正式运行是否一致

1. 脚本启动

最常见:

1
python app.py

适合:

  • 单文件练习
  • 小型脚本
  • 初学阶段的最小示例

优点:

  • 直观
  • 理解成本低

问题:

  • 项目一复杂,导入路径容易混乱
  • 多入口时不容易统一管理

2. 模块启动

例如:

1
python -m package_name.app

适合:

  • 已经有包结构的项目
  • 需要更稳定导入路径的项目

它的优势在于:让 Python 按模块方式理解项目,而不是仅仅把某个文件当脚本硬跑。

3. 命令行入口启动

再往后一些,会遇到:

  • CLI 工具
  • 测试 runner
  • 自动化任务入口

这时通常会把入口显式整理成:

  • 一个 main() 函数
  • 一个清晰的命令参数层
  • 一个稳定的执行入口

这类设计的价值,不在“写法高级”,而在于后面接 Jenkins、定时任务、容器执行时更稳定。

八、一个更像真实项目的最小目录应该长什么样

如果不想一开始就搞得很重,可以先用下面这个骨架:

1
2
3
4
5
6
7
8
9
demo_project/
├── app/
│ ├── __init__.py
│ ├── main.py
│ └── service.py
├── tests/
│ └── test_service.py
├── requirements.txt
└── README.md

app/service.py

1
2
3
4
5
6
7
def build_message(name: str) -> str:
if not isinstance(name, str):
raise TypeError("name must be str")
cleaned = name.strip()
if not cleaned:
raise ValueError("name can not be empty")
return f"hello, {cleaned}"

app/main.py

1
2
3
4
5
6
7
8
9
from app.service import build_message


def main() -> None:
print(build_message("python"))


if __name__ == "__main__":
main()

tests/test_service.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import pytest

from app.service import build_message


def test_build_message_success():
assert build_message("python") == "hello, python"


def test_build_message_empty():
with pytest.raises(ValueError):
build_message(" ")


def test_build_message_type_error():
with pytest.raises(TypeError):
build_message(123)

这个结构虽然小,但已经能直接拿来做三件事:

  • 本地运行
  • 写最小测试
  • 接 Jenkins 或命令行任务

因为它已经开始区分:

  • 业务逻辑放哪
  • 程序入口放哪
  • 测试放哪
  • 依赖放哪

九、把这套最小结构真正跑起来

如果按上面的目录落地,更推荐把整个流程走完整一次,而不是只看到目录就停下。

1
2
3
4
5
6
7
mkdir demo_project
cd demo_project
python3 -m venv .venv
source .venv/bin/activate
python -m pip install pytest
python app/main.py
pytest -q

第一次执行时,更稳一点的顺序是:

1
2
3
4
5
6
7
mkdir demo_project
cd demo_project
python3 -m venv .venv
source .venv/bin/activate
python -m pip install pytest
python app/main.py
pytest -q

如果是换机器重建环境,再使用:

1
python -m pip install -r requirements.txt

运行时重点观察四件事:

  • python 是否来自 .venv
  • pytest 是否能找到测试
  • from app.service import ... 是否导入正常
  • 失败时是代码问题还是环境问题

如果这里就出现报错,反而是好事,因为刚好可以借这一步把环境理解扎实。

十、为什么这个最小结构比“能跑就行”更重要

因为 Python 项目最容易出现的退化,就是从一个简单脚本开始,慢慢长成一团。

典型过程通常是这样的:

  1. 一开始只有一个文件
  2. 后来复制出第二个、第三个
  3. 又加了一些工具函数
  4. 又手动改了一些路径
  5. 又额外装了几个依赖
  6. 最后项目到底应该怎么启动已经说不清

所以入门阶段就把目录、环境、依赖、入口整理清楚,不是形式主义,而是在防止未来失控。

十一、最常见的错误写法

下面这些写法,几乎每个 Python 新手都会踩一两个。

1. 全局环境直接装所有依赖

问题:

  • 项目之间相互污染
  • 难以复现

错误写法:

1
pip install requests pytest flask

后果:

  • 当前项目能跑
  • 下一个项目可能被同样一套依赖污染
  • 过一段时间很难回忆这些包是给哪个项目装的

实际做法:

  • 每个项目单独建 venv

2. 直接用 pip install,但不确认解释器

问题:

  • 依赖装进了错误环境

错误写法:

1
2
pip install pytest
python -m pytest

可能看到:

1
No module named pytest

实际做法:

  • 优先用 python -m pip install

3. 项目里只有脚本,没有明确入口

问题:

  • 脚本都能跑,但运行方式各不相同
  • 后面接自动化流程时容易失控

实际做法:

  • 明确一个统一入口,例如 main.pypython -m app.main

例如:

错误写法:

1
2
3
python task1.py
python task2.py
python tmp_run.py

时间一长,很难分清谁才是正式入口。

修复写法:

1
python -m app.main

或者固定:

1
python main.py

4. requirements.txt 只是临时导出,不做筛选

问题:

  • 文件里充满无关依赖
  • 很难判断哪些是真正项目依赖

实际做法:

  • 小项目先手工维护核心依赖,保持清晰

例如:

更乱的 requirements.txt

1
2
3
4
5
6
black==24.4.2
coverage==7.5.1
Flask==3.0.3
ipython==8.24.0
pytest==8.2.0
requests==2.31.0

如果当前项目只是一个最小脚本工具,这里面就可能混入了不少“本机曾经装过但项目并不依赖”的包。

当前示例项目直接这样写:

1
pytest==8.2.0

十二、怎么测试这一层知识是不是真的掌握了

环境和启动方式不像业务功能那样直观,但依然可以测试。

1. 自测问题

可以让自己回答下面这些问题:

  • 当前项目到底用哪个 Python 解释器
  • 当前依赖到底装在哪
  • 删除虚拟环境后,能不能按文档重新搭起来
  • 换一台机器,能不能只靠 requirements.txt 跑起来

如果这些问题答不上来,说明还只是“会照着命令敲”,不算真正掌握。

2. 最小验证动作

更推荐做这几步验证:

  1. 删除旧虚拟环境
  2. 重新创建 .venv
  3. requirements.txt 安装依赖
  4. 运行主程序
  5. 运行测试

只要这五步能稳定重复,说明环境骨架基本是对的。

十三、一个真实项目里,这部分通常会在哪出问题

最常见的真实场景不是“本地完全跑不通”,而是下面这些半好半坏的问题:

  • 本地能跑,Jenkins 不能跑
  • 开发机能跑,服务器不能跑
  • 老项目之前能跑,过了一段时间突然不能跑
  • 同一项目在不同开发环境里跑出来的结果不一致

这类问题往往不是业务逻辑问题,而是下面这些基础环节出了偏差:

  • 解释器版本不一致
  • 依赖版本漂移
  • 启动方式不统一
  • 项目目录和导入路径设计不稳

所以这篇文章看起来像“入门篇”,其实它解决的是 Python 工程的底盘问题。

十四、一个实际排错场景:为什么本地能跑,Jenkins 一跑就报错

这类问题非常典型。

场景通常是这样:

  • 本地 IDE 已经自动选中了某个虚拟环境
  • 开发者直接点运行,一切正常
  • 代码提交后,Jenkins 在干净环境重新执行
  • 结果报 ModuleNotFoundError 或依赖版本错误

排查顺序更推荐这样走:

  1. 先确认 Jenkins 使用的解释器版本
  2. 再确认依赖是否按同一份 requirements.txt 安装
  3. 再确认启动命令是不是和本地一致
  4. 最后再看代码本身

这类场景里如果一看到报错就直接改代码,排查往往会被带偏。根因常常不在代码,而在运行入口和环境没有对齐。

例如,Jenkins 日志里可能看到:

1
ModuleNotFoundError: No module named 'pytest'

这时更合适的动作不是先改测试代码,而是先补下面这些输出:

1
2
3
4
python --version
which python
python -m pip --version
python -m pip list

如果要把这个排查过程做得更像工程实践,更推荐在 Jenkins 任务里先显式打印这些信息:

1
2
3
4
python --version
which python
python -m pip --version
python -m pip list

这样至少能先回答两个关键问题:

  • 当前到底用了哪个解释器
  • 当前环境到底装了哪些包

比起直接猜“是不是 pytest 版本不对”,这种排查更稳。

如果确认是环境问题,修复动作通常就是回到这组命令:

1
2
3
4
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
pytest -q

十五、一个实际练习

可以按下面这个练习自己完整做一遍。

目标:做一个命令行小工具,输入名字,输出欢迎语,并加上测试。

要求:

  1. 创建独立虚拟环境
  2. 安装 pytest
  3. build_message() 函数
  4. main() 作为统一入口
  5. 写至少 2 个测试
  6. 删除 .venv 后重新搭一遍

如果这 6 步能独立完成,说明这一篇最核心的实践已经真正掌握。

十六、这篇文章学完以后,下一步应该补什么

如果这篇文章已经理解,下一步最适合继续补的是:

  1. Python 基础语法怎么学才不会停留在玩具代码
  2. 列表、字典、集合这些内置容器为什么不只是“会用”
  3. 函数参数、可变对象、作用域为什么总是容易出错

原因很简单:环境和入口解决的是“代码怎么稳定跑起来”,而后面这些内容解决的是“代码为什么这样运行”。

十七、结语

这一篇最重要的,不是记住多少概念,而是亲手把下面这套动作做顺:

  • 建项目
  • 建虚拟环境
  • 安装依赖
  • 运行程序
  • 跑测试
  • 删除环境再重建

只要这套动作能稳定重复,Python 的入门就不是“会写几行代码”,而是真正开始具备工程起点了。