
utils.py 的诱人谎言
在每个 Python 项目中,总会在某个时候冒出一个熟悉的想法:
“这个逻辑以后或许有用。我先把它放到
utils.py里 。”
感觉很负责,很有前瞻性,几乎达到了专业水准。
短期内,这招确实管用。
六个月过去,utils.py 已经长达 1200 行。几乎没人记得其中一半函数是做什么用的。新来的开发者不敢碰它。老开发者宁愿复制粘贴也不愿重写——因为找到合适的工具比重写它要难得多。
如果你觉得这似曾相识,你并不孤单。
工具函数是不断增长的 Python 代码库中最常见(也是最有害)的模式之一。
当然,请注意,本文并非建议永远不要重用代码。而是想告诉你:停止将不相关的行为集中到通用的效用函数中。
工具函数通常都是出于良好的初衷:
你会看到类似这样的文件:
utils.pyhelpers.pycommon.pyshared.py它们里面是什么?
问题不在于重复利用,而在于脱离上下文的重用。
工具提供了灵活性,但它们却悄无声息地剥夺了其意义。
当你读到这样的代码时:
from utils import format_date, validate_input, process_data你几乎什么也学不到。
工具函数隐藏了意图,它们将领域知识扁平化为模糊的动词。
现在将其与以下内容进行比较:
from billing.dates import format_invoice_datefrom auth.validation import validate_login_payloadfrom orders.processing import process_pending_orders同样的重用,但清晰度截然不同。
上下午是可读代码与晦涩代码之间的区别。
过于庞大的工具代码库可能会以可预测的方式失败。
任何不适合放在其他任何地方的东西都会被放到工具类中。
最终:
每一项新增功能都显得合情合理。没有任何一项功能被移除。
最初只是“一个助手”,后来逐渐发展出规则:
def calculate_discount(price, user): if user.is_premium: return price * 0.8 return price那不是工具,而是伪装成通用逻辑的业务逻辑。
一旦业务规则存在于工具类中,它们就会变得:
工具函数通常:
但因为它们是“辅助函数”,开发人员对待它们不像对待核心逻辑那样谨慎。
在设计良好的系统中:
工具函数违反了这三点。
它们之所以存在,是因为我们一直在回避一个更难的问题:
“这种逻辑属于哪里?”
与其问,“我可以重复使用吗?”
而应该问:“这种行为代表了什么概念?”
然后将这种行为与该概念联系起来。
让我们来看看这在实践中的含义是什么。
不要使用全局的 utils.py,而是按领域进行组织。
以前:
# utils.pydef is_valid_email(email): ...现在:
# users/validation.pydef is_valid_email(email: str) -> bool: ...现在这个功能终于有了归宿。
它讲述了一个故事:这种逻辑之所以存在,是因为用户存在。
Python 模块很便宜且都是经过优化的,尽量使用它们。
而不是使用一个巨大的辅助文件utils.py。
而应该使用:
dates.pymoney.pystrings.pyserialization.py更好的选择:
billing/money.pyorders/serialization.pyreports/dates.py你不仅仅是在整理代码。
更是在对意图进行编码。
如果一个函数依赖于规则、配置或不断变化的行为——它可能不是一个工具函数。
以前:
def calculate_tax(amount, country): ...现在:
class TaxCalculator: def __init__(self, country): self.country = country def calculate(self, amount): ...这将使你获得:
类并非总是必要的——但人们常常使用工具函数来代替适当的抽象。
行为邻近性(behavioral proximity) 是 Python 中最被低估的模式之一。
如果逻辑操作作用于某个对象,请考虑将其添加到该对象上。
以前:
def is_order_refundable(order): ...现在:
class Order: def is_refundable(self) -> bool: ...现在你的代码读起来就像英文一样:
if order.is_refundable(): ...那不仅仅是更简洁,这样写的代码更诚实。
函数式辅助函数并不坏。
但它们的非结构化集合并不好。
不要将辅助函数集中在一起,而是按管道或转换进行分组。
# parsing.pydef parse_csv(...)def normalize_headers(...)# validation.pydef validate_schema(...)def validate_constraints(...)现在,重用是通过组合实现的,而不是通过便利实现的。
这就是它们如此危险的原因。
工具函数优化的是今天的速度,而不是明天的清晰度。
成本不会立即显现,
而是在以下情况才会展现出来:
良好的设计起初可能会感觉速度较慢,但之后速度会显著提升。
是的,凡事都有例外。
工具函数在满足以下条件时才有意义:
例如:
如果一个函数在任何项目中都适用,那么它很可能是一个工具函数。
但如果它只适用于单个项目,那么它就需要一个合适的归宿。
创建工具函数之前,请先问自己:
如果您对以上任何问题回答“是”——
那它就不是一个工具函数。
工具函数感觉无害。
它们觉得自己能帮上忙。
它们觉得自己很有成就感。
但随着时间的推移,它们会悄无声息地抹去代码中的含义。
当代码清晰、易读且诚实地表达意图时,Python 的优势就得以充分展现。
这并非来自庞大的辅助文件,而是来自恰当的行为。
所以,下次当你的手指敲击
utils.py时 ,请稍作停顿。
问问自己,逻辑究竟属于哪里。
未来的你和你的队友都会感谢你。
Thanks for your reading!
Enjoying coding, my friends! 🧑💻🧑💻🧑💻💯💯💯
推荐阅读👇👇👇
🌟 如果你觉得这篇文章对你有帮助,并且愿意支持我的话,你可以: 🌟
• 👍 点赞,让文章获得系统推荐 • ⤴️ 分享,把内容传递给身边的伙伴 • ❤️ 推荐,让文章影响到更多人 • 👏 欢迎留言交流,一起拓展技术的边界

👇👇👇 Follow me,获取更多高质量干货分享,我们下期再见!