函数该拆,当它同时处理不同抽象层的逻辑,如查库与渲染、校验与发请求;参数超3个未聚合、命名含“and/or/then”、返回类型混乱、测试需多mock,均是拆分信号。
函数是不是该拆?看它有没有「两件不相干的事」
一个函数干了多件事,不是代码多、行数长才叫“职责不清”,而是它在同时处理不同维度的逻辑。比如既查数据库又渲染 HTML,或者既校验输入又发 HTTP 请求——这两类动作天然属于不同抽象层。
实操建议:
问自己:如果我要给这个函数写单元测试,是否得 mock 数据库、网络、时间等至少两个外部依赖?如果是,大概率该拆
检查函数内部是否有明显分界:比如前半段处理
,后半段拼接
并执行,中间没共享状态,就是拆分信号
留意命名:如果函数名里带 “and”、“or”、“then”,比如
,基本是职责混合的铁证
参数超过 3 个时,先怀疑是不是封装错了
不是参数多就一定错,但 Python 的
函数一旦接受超过 3 个独立参数(不含
或
),往往意味着它在协调多个上下文,而没把关联数据聚合成一个概念。
常见错误现象:
—— 这些参数其实属于两个对象:
和
,硬塞进函数里会让调用方反复构造零散值。
立即学习
“
Python免费学习笔记(深入)
”;
实操建议:
把语义上成组的参数打包成 dataclass 或
,比如
避免用字典传参代替结构化类型,
看似简洁,实则隐藏了契约,IDE 和类型检查器都帮不上忙
如果函数必须支持多种组合(如部分字段可选),优先用
而非一堆
默认值
函数返回值类型混乱,说明它在承担「决策」和「执行」双重角色
比如一个叫
的函数,有时返回
(成功),有时抛
(校验失败),有时又返回
(余额不足但静默跳过)——这不是健壮,是职责模糊。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
使用场景:支付、权限校验、配置加载这类有明确成败路径的操作,最容易在这里失控。
实操建议:
让函数只做一件事:要么纯计算(无副作用、确定性返回),要么纯执行(有副作用、统一返回
或
类型)
拒绝“成功返回结果,失败返回
”模式;Python 有异常机制,就别用
当控制流
如果真需要多态返回(如
),说明它本该是多个小函数,或者用
模式(如
)
测试难写、难读、难改,根本原因常是函数边界没划清
当你发现要为一个函数写 5 个以上测试用例,且每个都要 patch 三四个地方(
、
、
),那不是测试写得不够好,是函数本身越界了。
性能影响:过度耦合的函数没法单独压测 IO 密集或 CPU 密集部分,也难以用
缓存中间结果。
实操建议:
每个测试文件只验证一种行为:比如
只管校验逻辑,不碰数据库;
只管对接第三方,不碰业务规则
如果某个函数的测试需要启动真实数据库或网络,立刻停手——它已经不属于 unit test 范畴,该被隔离出去
用
定义依赖接口(如
),而不是直接 import 具体实现,能倒逼你把职责切开
真正难的不是判断“要不要拆”,而是识别哪些逻辑看似相关、实则不该绑在一起——比如“生成订单号”和“保存订单”,前者是纯函数,后者是副作用,它们共享的只有“订单”这个名词,没有共享的执行上下文。
user_inputsql_queryvalidate_and_save_userdef*args**kwargscreate_order(user_id, product_id, quantity, currency, discount_code, notify_email)UserOrderRequestNamedTupleOrderRequest(product_id, quantity, discount_code)create_order(**order_dict)dataclasses.field(default_factory=...)Noneprocess_paymentdictValueErrorNoneboolResultNoneNoneUnion[str, int, None]Resultresult = process_payment(...); if result.is_ok(): ...patch('requests.post')patch('datetime.now')patch('os.getenv')functools.lru_cachetest_payment_validation.pytest_payment_gateway.pytyping.ProtocolPaymentGateway