✍️ 作者:王文峰(外号:神秘小峯 / 山峯)|中国国学、传统文化与代码爱好者的程序人生,期待你的关注和支持!
Python 工程化实战:写给 1 年经验开发者的 8 个习惯
-
- 一、开篇:一年经验的分水岭
- 二、习惯 1:代码规范——让工具管你
- 三、习惯 2:函数与模块的"专业感"
- 四、习惯 3:日志——print 的正确替代品
- 五、习惯 4:异常处理——别让错误静默消失
- 六、习惯 5:单元测试——pytest 十分钟上手
- 七、习惯 6:依赖管理——告别"在我电脑上能跑"
- 八、习惯 7:调试与排错——比 print 高效十倍
- 九、习惯 8:Code Review——协作的入场券
- 十、综合模板:一个"专业感"脚本长什么样
- 十一、总结与自测清单
- 🎯 学习教程(传送门)
- 🔥 往期文章

📚 这篇写给工作一年左右的 Python 开发者——你已经会写代码了,但"会写"和"写得专业"之间隔着 8 个习惯:规范、命名、日志、异常、测试、依赖管理、调试、Code Review。这不是语法课,是职业习惯课

一、开篇:一年经验的分水岭
刚工作一年,通常会遇到三个场景:
这三个痛点,恰好对应本文的八个习惯:代码可读(习惯 1~2)、可观测(习惯 3~4)、可验证(习惯 5~6)、可协作(习惯 7~8)。逐个来。
二、习惯 1:代码规范——让工具管你
业余写法:风格全凭手感,命名 a/b/temp1,一行 200 字符。 专业写法:格式化 + 检查工具开到最大,人不纠结风格。
# 四件套:格式化 + 排序 import + 静态检查 + 类型检查
pip install black isort ruff mypy
black . # 格式化(不用再争论空几格)
isort . # import 自动分组排序
ruff check . # 静态检查(坏味道、潜在 bug)
mypy . # 类型检查(配合类型注解)
配置写进 pyproject.toml,团队统一,CI 里跑一遍不通过不许合并:
[tool.black]
line-length = 100
[tool.ruff]
select = ["E", "F", "I", "B", "UP"]
命名速查(PEP 8 精华版):
| 变量/函数 | 小写下划线 | user_count、get_user() |
| 类 | 大驼峰 | UserService |
| 常量 | 全大写下划线 | MAX_RETRY = 3 |
| 模块/包 | 小写无下划线 | utils.py |
💡 类型注解是 1 年经验最该养成的习惯:def get_user(user_id: int) -> User:——可读性、mypy 检查、IDE 提示三丰收。
三、习惯 2:函数与模块的"专业感"
业余写法:一个函数 200 行,功能混杂,参数七八个。 专业写法:单一职责 + 参数对象 + 文档字符串。
# ❌ 业余:干了四件事,谁敢改?
def process(data, flag, mode, out_path, n):
...200 行...
# ✅ 专业:拆职责、收参数、带文档
from dataclasses import dataclass
@dataclass
class ProcessOptions:
mode: str = "fast"
batch_size: int = 100
out_path: str = "result.csv"
def clean_data(raw: list[dict]) –> list[dict]:
"""清洗原始数据:去空值、规整字段名。"""
...
def export_result(records: list[dict], options: ProcessOptions) –> Path:
"""导出结果到 CSV,返回文件路径。"""
...
三个专业细节:
- 函数不超过 30 行,超过就该拆;
- 参数超过 3 个用 dataclass/配置对象收拢;
- docstring 三要素:干什么、参数是什么、可能抛什么异常(Raises:)。
四、习惯 3:日志——print 的正确替代品
业余写法:满屏 print("ok"),上线前手动注释。 专业写法:分级别日志 + 统一配置,print 只配出现在教学代码里。
import logging
import sys
# 集中配置(放 logging_config.py,程序入口调用一次)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s [%(name)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[logging.StreamHandler(sys.stdout), logging.FileHandler("app.log", encoding="utf-8")],
)
log = logging.getLogger(__name__) # 每个模块用自己的 logger,name 便于定位
log.info("任务开始,共 %d 条", total) # 惰性格式化:用 %s 不用 f-string!
log.warning("重试第 %d 次:%s", attempt, err)
log.error("处理失败 doc_id=%s", doc_id, exc_info=True) # exc_info 自动带堆栈
级别使用规范:
| DEBUG | 开发调试细节,生产关闭 |
| INFO | 关键业务节点(开始/完成/总量) |
| WARNING | 异常但可继续(重试、降级) |
| ERROR | 操作失败,需要关注 |
| CRITICAL | 系统级故障 |
两个坑:①日志用 %s 惰性格式化(f-string 无论级别都会先求值,浪费性能);②别在日志里打敏感信息(密码、身份证、token)。
五、习惯 4:异常处理——别让错误静默消失
业余写法:except: pass,或把 print(e) 当处理。 专业写法:精确捕获 + 自定义异常 + 全局兜底。
class BizError(Exception):
"""业务异常基类:携带错误码,便于上层统一处理。"""
def __init__(self, code: str, message: str):
self.code = code
super().__init__(message)
def load_config(path: str) –> dict:
if not Path(path).exists():
raise BizError("CONFIG_MISSING", f"配置文件不存在:{path}") # 主动抛,语义清晰
...
try:
cfg = load_config("app.yaml")
except BizError as e: # 精确捕获业务异常
log.error("加载配置失败 code=%s msg=%s", e.code, e)
cfg = DEFAULT_CONFIG # 明确的降级策略
except OSError as e: # 精确捕获系统异常
log.error("IO 异常", exc_info=True)
raise # 处理不了就继续抛,别硬吞
三条铁律:
六、习惯 5:单元测试——pytest 十分钟上手
业余写法:从不写测试,“我跑过一遍没问题”。 专业写法:核心逻辑必有测试,改动后跑一遍就有底气。
# tests/test_pricing.py
import pytest
from myshop.pricing import calc_discount
@pytest.mark.parametrize("amount,level,expected", [
(100, "vip", 80), # 8 折
(100, "normal", 100), # 不打折
(0, "vip", 0),
(–1, "vip", 0), # 边界:负数视为 0
])
def test_calc_discount(amount, level, expected):
assert calc_discount(amount, level) == expected
def test_invalid_level_raises():
with pytest.raises(ValueError):
calc_discount(100, "unknown") # 异常路径也要测
pytest -q # 跑全部测试
pytest –cov=myshop tests/ # 看覆盖率(核心逻辑 ≥ 80%)
新手最容易漏的两类测试:边界值(0、空、超大)和异常路径(传错类型、文件不存在)。pytest 的 parametrize 一个装饰器搞定一组用例。
七、习惯 6:依赖管理——告别"在我电脑上能跑"
业余写法:全局 pip install,README 写"先装 requests、pandas……"。 专业写法:虚拟环境 + 依赖锁定,每人环境一致。
# ① 每个项目一个虚拟环境
python -m venv .venv
source .venv/bin/activate # Windows: .venv\\Scripts\\activate
# ② 装依赖并锁定版本
pip install requests pandas
pip freeze > requirements.txt # 锁版本:requests==2.32.3
# ③ 换机器复现环境
pip install -r requirements.txt
配套三件:
- .gitignore 里加 .venv/、__pycache__/、*.log、.env;
- 敏感配置(密钥)走 .env + python-dotenv,.env 不进 git;
- 用 pyproject.toml 管理项目元信息(新项目标准姿势)。
八、习惯 7:调试与排错——比 print 高效十倍
业余写法:出问题就 print 大法,一行行挪。 专业写法:四件套,按顺序用:
| pdb/ipdb | 断点调试,看现场 | python -m pdb script.py / 代码里 breakpoint() |
| traceback | 看完整堆栈 | 出错时别只看最后一行 |
| logging + exc_info | 生产排错的唯一依据 | log.error("xx", exc_info=True) |
| cProfile | 性能瓶颈定位 | python -m cProfile -s tottime script.py |
# breakpoint():Python 3.7+ 内置断点,比满屏 print 干净
def calc(items):
total = 0
breakpoint() # 程序在此暂停,进 ipdb/pdb,可敲变量名看现场
for it in items:
total += it.price
return total
排错方法论(比工具更重要):
九、习惯 8:Code Review——协作的入场券
业余写法:代码写完直接提交,PR 描述就一句"功能完成"。 专业写法:提交规范 + 自审清单,让 reviewer 喜欢你的代码。
git commit -m "feat: 订单导出增加按日期筛选" # feat/fix/docs/refactor/test
提交前自审清单(贴墙上):
- ✅ 有没有调试用的 print/breakpoint() 残留?
- ✅ 命名看得懂吗?有没有 data1/tmp2?
- ✅ 异常路径处理了吗?有没有裸 except?
- ✅ 日志级别用对了吗?打了敏感信息吗?
- ✅ 核心逻辑有测试吗?
- ✅ black/ruff/mypy 三关过了吗?
看别人的 Review 也要带着学习心态——别人提的每一条意见,都是免费的经验值。
十、综合模板:一个"专业感"脚本长什么样
把八个习惯合起来,日常脚本的标准形态:
#!/usr/bin/env python3
"""数据清洗脚本:python clean.py input.csv output.csv
Raises:
FileNotFoundError: 输入文件不存在时。
"""
import argparse
import logging
import sys
from pathlib import Path
logging.basicConfig(level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger(__name__)
def clean(in_path: Path, out_path: Path) –> int:
if not in_path.exists():
raise FileNotFoundError(f"输入文件不存在:{in_path}")
rows = 0
with in_path.open(encoding="utf-8") as fin, out_path.open("w", encoding="utf-8") as fout:
for line in fin:
if line.strip():
fout.write(line)
rows += 1
return rows
def main() –> int:
parser = argparse.ArgumentParser(description="清洗 CSV 空行")
parser.add_argument("input", type=Path)
parser.add_argument("output", type=Path)
args = parser.parse_args()
try:
n = clean(args.input, args.output)
except FileNotFoundError as e:
log.error("%s", e)
return 2
log.info("清洗完成:%d 行 -> %s", n, args.output)
return 0
if __name__ == "__main__":
sys.exit(main())
过一遍自检:类型注解 ✅ 文档字符串 ✅ 日志 ✅ 异常 ✅ 退出码 ✅ argparse ✅——这就是"专业"的样子,总共不到 40 行。
十一、总结与自测清单
- ✅ 规范交给工具:black + isort + ruff + mypy 四件套进 CI;
- ✅ 函数 ≤ 30 行、参数 ≤ 3 个、docstring 三要素、类型注解必写;
- ✅ 日志分级使用,惰性格式化 %s,敏感信息绝不入日志;
- ✅ 异常三铁律:不裸 except、捕获必有动作、raise from 保链条;
- ✅ pytest 覆盖边界值 + 异常路径,核心逻辑 ≥ 80% 覆盖率;
- ✅ 虚拟环境 + requirements.txt 锁版本,.env 管密钥;
- ✅ 排错四件套:breakpoint()、完整堆栈、二分定位、最小复现;
- ✅ 提交规范 + 自审清单,是你协作能力的名片。
下一篇:《并发篇——多线程、多进程与 asyncio 异步编程》(GIL 真相 + 场景选型),敬请关注!
🎯 学习教程(传送门)
| 01 | JAVA | 从入门到进阶的系统知识 | 持续写作中…… |
| 02 | Oracle | 数据库从用法到实战 | 创作中…… |
| 03 | vbs脚本 | 手把手教你做脚本 | 完善中…… |
| 04 | IDEA | 牛逼哄哄的编程利器 | 编写中…… |
| 05 | 面试 | 吐血整理的面试技巧 | 更新中…… |

🔥 往期文章
🧭 精选往期好文,更多请移步 我的博客主页
- 📕 平安壹钱包面试官:请你说一下Mybatis的实现原理
- 📗 Java开发-热点-热门问题精华核心总结-推荐
- 📘 第一章:日常_JAVA_面试题集15(含答案)
- 📙 第二章:日常_JAVA_面试题集14(含答案)
- 📚 往期文章大全……

👍 点赞 + ⭐ 收藏 + 💬 评论,一键三连走起! 你们的支持,是我持续创作的最大动力~

✨ 以上就是今天的全部内容,关注我,技术之路不迷路!
📖 本人详解 ✍️ 作者:王文峰,参与 CSDN 2020 年度博客之星评选,《Java王大师王天师》,外号:神秘小峯 / 山峯 🏮 中国国学、传统文化与代码爱好者的程序人生,期待你的关注和支持! 🔗 转载说明:务必注明来源(注明:作者:王文峰哦)
