Python 项目管理
安装 uv.
管理 Python
下载 Python,并查看本机已安装的 Python:
PS C:\Users\Shy_Vector\AAA> uv python install pypyPS C:\Users\Shy_Vector\AAA> uv python listcpython-3.15.0a6-windows-x86_64-none <download available>cpython-3.15.0a6+freethreaded-windows-x86_64-none <download available>cpython-3.14.3-windows-x86_64-none <download available>cpython-3.14.3+freethreaded-windows-x86_64-none <download available>cpython-3.13.12-windows-x86_64-none <download available>cpython-3.13.12+freethreaded-windows-x86_64-none <download available>cpython-3.12.13-windows-x86_64-none <download available>cpython-3.12.10-windows-x86_64-none C:\Program Files\Python\python.execpython-3.11.15-windows-x86_64-none <download available>cpython-3.10.20-windows-x86_64-none <download available>cpython-3.9.25-windows-x86_64-none <download available>cpython-3.8.20-windows-x86_64-none <download available>pypy-3.11.13-windows-x86_64-none C:\Users\Shy_Vector\AppData\Roaming\uv\python\pypy-3.11.13-windows-x86_64-none\pypy3.11.exepypy-3.10.16-windows-x86_64-none <download available>pypy-3.9.19-windows-x86_64-none <download available>pypy-3.8.16-windows-x86_64-none <download available>graalpy-3.12.0-windows-x86_64-none <download available>graalpy-3.11.0-windows-x86_64-none <download available>graalpy-3.10.0-windows-x86_64-none <download available>临时运行特定版本的 Python / 脚本:
PS C:\Users\Shy_Vector\AAA> uv run -p 3.12 python
Python 3.12.10 (tags/v3.12.10:0cc8128, Apr 8 2025, 12:21:36) [MSC v.1943 64 bit (AMD64)] on win32Type "help", "copyright", "credits" or "license" for more information.Ctrl click to launch VS Code Native REPL>>> exit()
PS C:\Users\Shy_Vector\AAA> uv run -p pypy python
Python 3.11.13 (413c9b7f57f5, Jul 03 2025, 18:04:37)[PyPy 7.3.20 with MSC v.1941 64 bit (AMD64)] on win32Type "help", "copyright", "credits" or "license" for more information.Ctrl click to launch VS Code Native REPL>>>> exit()删除 Python:
PS C:\Users\Shy_Vector\AAA> uv python uninstall pypySearching for Python versions matching: PyPyUninstalled Python 3.11.13 in 777ms - pypy-3.11.13-windows-x86_64-none管理 venv
初始化项目:
PS C:\Users\Shy_Vector\AAA> uv init -p 3.12
Initialized project `AAA`
PS C:\Users\Shy_Vector\AAA> ls
目录: C:\Users\Shy_Vector\AAA
Mode LastWriteTime Length Name---- ------------- ------ -----a---- 2026/3/4 10:53 109 .gitignore-a---- 2026/3/4 10:53 5 .python-version-a---- 2026/3/4 10:46 167 main.py-a---- 2026/3/4 10:53 154 pyproject.toml-a---- 2026/3/4 10:53 0 README.md可在 .python-version 中修改当前项目的 Python 版本:
3.12pyproject.toml 包含当前项目的配置信息,第三方工具零散的配置文件得到统一:
[project]name = "AAA"version = "0.1.0"description = "AAAAAA"readme = "README.md"requires-python = ">=3.12"dependencies = []初始化之前已有 main.py,
from flask import Flask
app = Flask(__name__)
@app.route('/')def foo(): return 'Hello World'
if __name__ == '__main__': app.run(debug=True)里面依赖了 flask 第三方库,接下来我们安装它:
PS C:\Users\Shy_Vector\AAA> uv add flaskUsing CPython 3.12.10 interpreter at: C:\Program Files\Python\python.exeCreating virtual environment at: .venvResolved 9 packages in 1.41sPrepared 8 packages in 533msInstalled 8 packages in 26ms + blinker==1.9.0 + click==8.3.1 + colorama==0.4.6 + flask==3.1.3 + itsdangerous==2.2.0 + jinja2==3.1.6 + markupsafe==3.0.3 + werkzeug==3.1.6--dev对于
uv add的参数,可以使用--dev参数将工具加入开发依赖组,组内的依赖仅在开发阶段被使用,不会被打包出去.Terminal window uv add ruff --dev.pyproject.toml [project]name = "AAA"version = "0.1.0"description = "AAAAAA"readme = "README.md"requires-python = ">=3.12"dependencies = ["flask>=3.1.3",][dependency-groups]dev = ["ruff>=0.15.4",]当然,
ruff是工具而不是依赖,与工程代码无关,不应该作为依赖引入.Terminal window uv remove ruff --dev
uv tool对于工具,可以使用
uv tool install来安装:Terminal window PS C:\Users\Shy_Vector\AAA> uv tool install ruffResolved 1 package in 265msInstalled 1 package in 15ms+ ruff==0.15.4Installed 1 executable: ruffPS C:\Users\Shy_Vector\AAA> which ruffC:\Users\Shy_Vector\.local\bin\ruff.EXEPS C:\Users\Shy_Vector\AAA> ruff checkAll checks passed!查看所有工具:
Terminal window PS C:\Users\Shy_Vector\AAA> uv tool listruff v0.15.4- ruff
我们可以看到 uv 已经为当前项目自动创建虚拟环境 .venv:
PS C:\Users\Shy_Vector\AAA> tree文件夹 PATH 列表卷序列号为 EA1E-9D15C:.├─.ruff_cache│ └─0.15.4└─.venv ├─Lib │ └─site-packages │ ├─blinker │ │ └─__pycache__ │ ├─blinker-1.9.0.dist-info │ ├─click │ │ └─__pycache__ │ ├─click-8.3.1.dist-info │ │ └─licenses │ ├─colorama │ │ ├─tests │ │ └─__pycache__ │ ├─colorama-0.4.6.dist-info │ │ └─licenses │ ├─flask │ │ ├─json │ │ │ └─__pycache__ │ │ ├─sansio │ │ │ └─__pycache__ │ │ └─__pycache__ │ ├─flask-3.1.3.dist-info │ │ └─licenses │ ├─itsdangerous │ │ └─__pycache__ │ ├─itsdangerous-2.2.0.dist-info │ ├─jinja2 │ │ └─__pycache__ │ ├─jinja2-3.1.6.dist-info │ │ └─licenses │ ├─markupsafe │ │ └─__pycache__ │ ├─markupsafe-3.0.3.dist-info │ │ └─licenses │ ├─werkzeug │ │ ├─datastructures │ │ │ └─__pycache__ │ │ ├─debug │ │ │ ├─shared │ │ │ └─__pycache__ │ │ ├─middleware │ │ ├─routing │ │ │ └─__pycache__ │ │ ├─sansio │ │ │ └─__pycache__ │ │ ├─wrappers │ │ │ └─__pycache__ │ │ └─__pycache__ │ ├─werkzeug-3.1.6.dist-info │ │ └─licenses │ └─__pycache__ └─Scripts虚拟环境何以实现?当虚拟环境被激活后,
.venv\\Lib\\site-packages目录将被追加进 Python 中sys.path列表:>>> import sys, pprint>>> pprint.pp(sys.path)['','C:\\Program Files\\Python\\python312.zip','C:\\Program Files\\Python\\DLLs','C:\\Program Files\\Python\\Lib','C:\\Program Files\\Python','C:\\Users\\Shy_Vector\\AAA\\.venv','C:\\Users\\Shy_Vector\\AAA\\.venv\\Lib\\site-packages']Python 在导入模块时,将逐个检查
sys.path列表里的每个路径,直到找出该模块.
查看所有第三方库的依赖关系:
PS C:\Users\Shy_Vector\AAA> uv treeResolved 9 packages in 1msAAA v0.1.0└── flask v3.1.3 ├── blinker v1.9.0 ├── click v8.3.1 │ └── colorama v0.4.6 ├── itsdangerous v2.2.0 ├── jinja2 v3.1.6 │ └── markupsafe v3.0.3 ├── markupsafe v3.0.3 └── werkzeug v3.1.6 └── markupsafe v3.0.3现在运行 main.py:
PS C:\Users\Shy_Vector\AAA> uv run main.py * Serving Flask app 'main' * Debug mode: onWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on http://127.0.0.1:5000Press CTRL+C to quit * Restarting with stat * Debugger is active! * Debugger PIN: 329-036-685127.0.0.1 - - [04/Mar/2026 10:59:36] "GET / HTTP/1.1" 200 -我拿到的是别人的项目,怎么配环境?难不成只能看
pyproject.toml,一个个手动uv add?当然不需要!只需Terminal window PS C:\Users\Shy_Vector\AAA> uv syncuv 就会读取
pyproject.toml,自动搭建虚拟环境,并安装好所有依赖.
Python 往事如果只用 Python 官方的工具管理项目,那么流程是:手动创建虚拟环境
.venv并激活,编辑并读取pyproject.toml,往.venv安装依赖.Terminal window python -m venv .venvsource .venv/bin/activate (.venv\\Scripts\\activate)edit pyproject.tomlpip install -e .
.venv可以取别的名字,但.venv这个名字已经被各界认同,也便于 IDE 识别.
pip install -e .是自安装:
pip先读取pyproject.toml,把当前项目打包成标准的 Python 软件包;
pip会像安装任何第三包那样,安装刚刚打包好的软件包 (含依赖).
- 当前项目的源代码也会被打包进去 (比如
main.py也被放进了site-packages目录下);- 这样做的好处是:我们的源代码在导入本项目别的代码时,可以不用相对导入 (如
from . import foo),而用绝对导入 (如import AAA.foo),这样写会与项目使用者写法保持一致,语义更清晰;- 但这样就存在两份一样的源代码,会引入修改同步问题.此时使用
-e参数 (编辑模式),site-packages目录下的源代码将变成链接文件,指向项目源代码.
uv run已经自动在运行脚本之前帮我们自安装好啦,不用操心.
Python 传说在 Python 官方没有标准规定
pyproject.toml文件之前,若想让别人复现这个环境,需使用Terminal window pip freeze > requirements.txt把所有包导出到
requirements.txt:requirements.txt flask==3.1.3blinker==1.9.0click==8.3.1itsdangerous==2.2.0jinja2==3.1.6markupsafe==3.0.3werkzeug==3.1.6但
requirements.txt混合了所有的直接或间接依赖,很难维护 (比如删除flask之后,剩余的间接依赖仍被保留,因为requirements.txt并不包含依赖关系的信息).
项目结构
flat layout:
AAA├─AAA│ ├─app.py│ ├─bar.py│ └─foo.py├─...├─docs├─...├─tests├─...├─pyproject.toml├─README.md└─...src layout:
AAA├─docs├─...├─src│ └─AAA│ ├─app.py│ ├─bar.py│ └─foo.py├─tests├─...├─pyproject.toml├─README.md└─...为什么要套娃如果没有套一层,项目打包并解压到
site-packages后,根目录的源代码会裸露在site-packages里,此时会有导入污染的问题:import app, bar, foo # 万一同时有 AAA.app 和 BBB.app 怎么办?如果套了一层,就不会有这个污染问题:
import AAA.appfrom AAA import app, bar, foo
打包
认识.whl当我们使用
pip,uv,poetry这些工具安装软件包时,都会在 PyPI 下载相应的.whl文件 (如flask-3.1.3-py3-none-any.whl),其本质就是压缩包.所谓的
pip install,就是将.whl压缩包解压到site-packages目录里Terminal window └─.venv├─Lib│ └─site-packages│ ├─__pycache__│ ├─...│ ├─AAA│ │ ├─__pycache__│ │ ├─module│ │ │ ├─cat.py│ │ │ ├─dog.py│ │ │ └─...│ │ ├─app.py│ │ ├─bar.py│ │ ├─foo.py│ │ └─...│ ├─AAA-0.1.0.dist-info│ │ └─...│ ├─...│ ├─flask│ │ ├─__pycache__│ │ └─...│ ├─flask-3.1.3.dist-info│ │ └─...│ └─...└─Scripts
flask目录存放着该库的所有源代码,此时可以使用import flask.app来导入app.py文件.flask-3.1.3.dist-info目录里的METADATA文件由pyproject.toml生成,记录了所需依赖.
Python 构建系统
.whl文件如何生成?Python 的构建系统分为前端 (命令行工具,官方推荐工具为
build) 和后端 (把项目代码打包成.whl文件,默认使用setuptools作为后端).由于 PEP 517 规范 把前后端之间的交互接口定义得十分清晰,社区涌现了许多第三方实现,如flit,hatchling,uv,poetry,PDM等,它们都可以作为前端和后端,可以自由组合.
安装 build:
pip install build根据 hatchling 的要求,配置 pyproject.toml:
[project]name = "AAA"version = "0.1.0"description = "AAAAAA"readme = "README.md"requires-python = ">=3.12"dependencies = [ "flask>=3.1.3",]
[build-system]requires = ["hatchling"]build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]packages = ["src/AAA"]现在可以打包了:
PS C:\Users\Shy_Vector\AAA> python -m build* Creating isolated environment: venv+pip...* Installing packages in isolated environment: - hatchling* Getting build dependencies for sdist...* Building sdist...* Building wheel from sdist* Creating isolated environment: venv+pip...* Installing packages in isolated environment: - hatchling* Getting build dependencies for wheel...* Building wheel...Successfully built AAA-0.1.0.tar.gz and AAA-0.1.0-py3-none-any.whl也可以使用
uv作为前端:uv build,比build快.
打包出来的 .whl 和 .tar.gz 存放在项目的 dist 目录里:
PS C:\Users\Shy_Vector\AAA> unzip -l ./dist/AAA-0.1.0-py3-none-any.whlArchive: ./dist/AAA-0.1.0-py3-none-any.whl Length Date Time Name--------- ---------- ----- ---- 162 2020/02/02 00:00 AAA/main.py 128 2020/02/02 00:00 AAA-0.1.0.dist-info/METADATA 87 2020/02/02 00:00 AAA-0.1.0.dist-info/WHEEL 280 2020/02/02 00:00 AAA-0.1.0.dist-info/RECORD--------- ------- 657 4 files__init__.py
hatchling默认支持 src layout.只需要添加空文件
__init__.py让hatchling认为其所在的目录AAA可打包.pyproject.toml [project]name = "AAA"version = "0.1.0"description = "AAAAAA"readme = "README.md"requires-python = ">=3.12"dependencies = ["flask>=3.1.3",][build-system]requires = ["hatchling"]build-backend = "hatchling.build"[tool.hatch.build.targets.wheel]packages = ["src/AAA"]Terminal window PS C:\Users\Shy_Vector\AAA> python -m buildPS C:\Users\Shy_Vector\AAA> unzip -l ./dist/AAA-0.1.0-py3-none-any.whlArchive: ./dist/AAA-0.1.0-py3-none-any.whlLength Date Time Name--------- ---------- ----- ----0 2020/02/02 00:00 AAA/__init__.py162 2020/02/02 00:00 AAA/main.py128 2020/02/02 00:00 AAA-0.1.0.dist-info/METADATA87 2020/02/02 00:00 AAA-0.1.0.dist-info/WHEEL354 2020/02/02 00:00 AAA-0.1.0.dist-info/RECORD--------- -------731 5 files
可以 pip install 或者 uv add 将 .whl 文件解压至 .venv\\Lib\\site-packages,实现软件包的安装.