一、背景
上一篇整理了 Python 常用标准库。
这一篇继续整理 Python 项目开发中非常基础,但又很容易被忽略的内容:
- 虚拟环境
requirements.txt.env配置文件- 项目目录如何组织
- 如何写一个可复用的小工具包
如果只是写几十行临时脚本,可以把所有代码都放在一个 .py 文件里。
但是当脚本越来越多,或者一个项目需要多人维护时,就需要关注环境隔离、依赖管理、配置管理和目录结构。
二、为什么需要虚拟环境
如果所有 Python 项目都共用系统 Python 环境,很容易出现依赖冲突。
例如:
项目 A 需要 requests==2.28.0
项目 B 需要 requests==2.31.0
如果两个项目都安装在系统 Python 里,就可能互相影响。
虚拟环境的作用是:给每个项目创建一套独立的依赖目录。
这样不同项目可以使用不同版本的第三方库。
三、venv 创建虚拟环境
Python3 自带 venv 模块。
进入项目目录后执行:
python -m venv .venv
这会在当前项目下创建一个 .venv 目录。
目录大概如下:
.venv/
bin/
include/
lib/
pyvenv.cfg
Windows 下目录结构会有些不同,一般会有:
.venv/
Scripts/
Lib/
pyvenv.cfg
四、激活虚拟环境
macOS 或 Linux:
source .venv/bin/activate
Windows:
.venv\Scripts\activate
激活后,命令行前面通常会出现类似:
(.venv)
这表示当前 shell 已经进入虚拟环境。
查看当前 Python:
which python
python --version
python -m pip --version
Windows 使用:
where python
python --version
python -m pip --version
退出虚拟环境:
deactivate
五、在虚拟环境中安装依赖
激活虚拟环境后安装依赖:
python -m pip install requests
确认安装位置:
python -m pip show requests
查看当前环境所有依赖:
python -m pip list
这里建议一直使用:
python -m pip
而不是直接使用:
pip
这样可以减少 pip 和 Python 环境不一致的问题。
六、requirements.txt
requirements.txt 用来记录项目依赖。
安装几个依赖后,可以执行:
python -m pip freeze > requirements.txt
文件内容类似:
requests==2.31.0
pymysql==1.1.0
python-dotenv==1.0.0
其他机器上安装依赖:
python -m pip install -r requirements.txt
这样别人拿到项目后,不需要一个个手动安装依赖。
七、requirements.txt 的使用建议
pip freeze 会导出当前环境里的所有包。
如果当前环境已经安装了很多无关依赖,生成出来的 requirements.txt 也会很乱。
所以建议:
- 每个项目单独创建虚拟环境
- 只在项目虚拟环境里安装项目需要的依赖
- 在干净环境中生成
requirements.txt - 不要把系统 Python 的依赖直接导出来
如果只是手动维护,也可以自己写:
requests==2.31.0
pymysql==1.1.0
python-dotenv==1.0.0
比起导出一大堆无关依赖,手写核心依赖有时更清楚。
八、.env 配置文件
项目中经常会有一些配置,例如:
- 数据库地址
- 数据库用户名
- 数据库密码
- 接口地址
- 运行环境
这些内容不建议直接写死在代码里。
可以放到 .env 文件中。
例如:
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=root
MYSQL_DATABASE=test
APP_ENV=dev
然后在代码里读取。
九、使用 os 读取环境变量
如果环境变量已经存在,可以直接使用 os.getenv():
import os
mysql_host = os.getenv("MYSQL_HOST", "127.0.0.1")
mysql_port = int(os.getenv("MYSQL_PORT", "3306"))
print(mysql_host)
print(mysql_port)
第二个参数是默认值。
这种写法适合服务器上通过环境变量传配置。
十、使用 python-dotenv 读取 .env
本地开发时,可以使用 python-dotenv 读取 .env 文件。
安装:
python -m pip install python-dotenv
代码:
import os
from dotenv import load_dotenv
load_dotenv()
mysql_host = os.getenv("MYSQL_HOST", "127.0.0.1")
mysql_port = int(os.getenv("MYSQL_PORT", "3306"))
print(mysql_host)
print(mysql_port)
这样本地开发时可以把配置写在 .env 中,代码中统一从环境变量读取。
十一、.env 不要提交到 Git
.env 中可能包含密码、Token、密钥等敏感信息。
所以一般要加入 .gitignore:
.env
.venv/
可以提供一个 .env.example 作为模板。
例如:
MYSQL_HOST=127.0.0.1
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=please_change
MYSQL_DATABASE=test
APP_ENV=dev
提交 .env.example,不要提交真实 .env。
十二、项目目录如何组织
一个简单 Python 项目可以这样组织:
demo_project/
README.md
requirements.txt
.env.example
.gitignore
main.py
config.py
utils/
__init__.py
file_utils.py
date_utils.py
logs/
data/
说明:
| 路径 | 作用 |
|---|---|
README.md |
项目说明 |
requirements.txt |
项目依赖 |
.env.example |
配置模板 |
.gitignore |
Git 忽略规则 |
main.py |
程序入口 |
config.py |
配置读取 |
utils/ |
通用工具函数 |
logs/ |
日志目录 |
data/ |
数据文件目录 |
小项目不需要一开始就设计得很复杂。
先做到:
- 入口清楚
- 配置独立
- 工具函数独立
- 依赖可复现
- 敏感信息不进 Git
十三、main.py 作为入口
main.py 可以作为程序入口。
from utils.date_utils import now_text
def main():
print("程序开始")
print(now_text())
if __name__ == "__main__":
main()
if __name__ == "__main__": 的作用是:
- 直接运行当前文件时执行
main() - 被其他模块导入时不自动执行
main()
这是 Python 项目中非常常见的写法。
十四、config.py 读取配置
可以把配置读取统一放在 config.py。
import os
from dotenv import load_dotenv
load_dotenv()
MYSQL_CONFIG = {
"host": os.getenv("MYSQL_HOST", "127.0.0.1"),
"port": int(os.getenv("MYSQL_PORT", "3306")),
"user": os.getenv("MYSQL_USER", "root"),
"password": os.getenv("MYSQL_PASSWORD", ""),
"database": os.getenv("MYSQL_DATABASE", "test"),
}
其他模块需要数据库配置时,直接导入:
from config import MYSQL_CONFIG
print(MYSQL_CONFIG)
这样配置读取逻辑不会散落在各个文件中。
十五、写一个可复用的小工具包
假设项目里经常要处理文件,可以写一个 utils/file_utils.py。
from pathlib import Path
def read_text(path):
return Path(path).read_text(encoding="utf-8")
def write_text(path, content):
file_path = Path(path)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content, encoding="utf-8")
再写一个 utils/date_utils.py。
from datetime import datetime
def now_text():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
utils/__init__.py 可以先留空。
使用:
from utils.file_utils import read_text, write_text
from utils.date_utils import now_text
write_text("data/hello.txt", now_text())
print(read_text("data/hello.txt"))
十六、工具函数怎么拆
工具函数不要一开始就拆得太碎。
比较实用的拆分方式是按功能分类:
utils/
file_utils.py
date_utils.py
json_utils.py
db_utils.py
log_utils.py
每个文件只放相关能力。
例如:
| 文件 | 适合放什么 |
|---|---|
file_utils.py |
文件读写、目录创建、文件遍历 |
date_utils.py |
日期格式化、时间转换 |
json_utils.py |
JSON 读写 |
db_utils.py |
数据库连接、查询封装 |
log_utils.py |
日志初始化 |
如果某个函数只在一个地方使用,不一定要马上抽到 utils 里。
当它被多个模块重复使用时,再抽出来更合适。
十七、不要把所有东西都放 utils
utils 很方便,但也容易变成杂物间。
不建议把业务逻辑都放到 utils 里。
例如一个爬虫项目,可以这样组织:
spider_project/
main.py
config.py
crawler/
__init__.py
client.py
parser.py
pipeline.py
utils/
__init__.py
file_utils.py
log_utils.py
说明:
crawler/client.py放请求逻辑crawler/parser.py放解析逻辑crawler/pipeline.py放保存逻辑utils/只放通用工具
这样项目结构会比全部堆在 utils 中更清楚。
十八、.gitignore 常见配置
Python 项目中常见 .gitignore:
.venv/
__pycache__/
*.pyc
.env
.DS_Store
logs/
*.log
说明:
| 规则 | 说明 |
|---|---|
.venv/ |
虚拟环境目录 |
__pycache__/ |
Python 字节码缓存 |
*.pyc |
编译缓存文件 |
.env |
本地敏感配置 |
.DS_Store |
macOS 系统文件 |
logs/ |
日志目录 |
*.log |
日志文件 |
虚拟环境和日志都不应该提交到 Git。
十九、一个完整小项目示例
最终目录:
demo_project/
README.md
requirements.txt
.env.example
.gitignore
main.py
config.py
utils/
__init__.py
date_utils.py
file_utils.py
.gitignore:
.venv/
__pycache__/
*.pyc
.env
*.log
.env.example:
APP_ENV=dev
OUTPUT_FILE=data/output.txt
requirements.txt:
python-dotenv==1.0.0
config.py:
import os
from dotenv import load_dotenv
load_dotenv()
APP_ENV = os.getenv("APP_ENV", "dev")
OUTPUT_FILE = os.getenv("OUTPUT_FILE", "data/output.txt")
utils/date_utils.py:
from datetime import datetime
def now_text():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
utils/file_utils.py:
from pathlib import Path
def write_text(path, content):
file_path = Path(path)
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content, encoding="utf-8")
main.py:
from config import APP_ENV, OUTPUT_FILE
from utils.date_utils import now_text
from utils.file_utils import write_text
def main():
content = f"env={APP_ENV}, time={now_text()}\n"
write_text(OUTPUT_FILE, content)
print("写入完成:", OUTPUT_FILE)
if __name__ == "__main__":
main()
运行:
python -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
cp .env.example .env
python main.py
二十、总结
这一篇主要整理了 Python 虚拟环境和项目结构。
需要重点记住:
- 每个项目尽量使用独立虚拟环境
- 使用
python -m venv .venv创建虚拟环境 - 使用
requirements.txt固定依赖 - 本地敏感配置放
.env,不要提交到 Git - 可以提交
.env.example作为配置模板 - 小项目可以从
main.py、config.py、utils/开始组织 - 工具函数按功能拆分,不要把业务逻辑都塞进
utils .venv/、__pycache__/、.env、日志文件都应该放进.gitignore
把这些基础做好后,后续不管是写爬虫、数据处理脚本,还是写 Web 服务,项目都会更容易维护。