
我接手过一些代码——来自很牛的开发者,却依然让我盯着屏幕发呆:“等等……这到底在做什么?”
这种停顿,代价很大。
可读性高的代码,不是代码写得少,而是代码写得明显。它不需要注释就能自解释,不需要发Slack问同事,更不用六个月后自己打开文件时,内心充满疑惑。
今天分享10个我每天都在用的可读性技巧。大部分Python开发者都知道,但真正用对的,没几个。
布尔标志是可读性的第一杀手。
# ❌ 糟糕的写法defprocess(data, fast=True, safe=False): ...# 调用代码:fast=True, safe=False 是什么意思?process(user_data, True, False)现在不看函数定义,你能回答:fast=True, safe=False 代表什么业务含义吗?
改用意图清晰的枚举类:
# ✅ 可读的写法classMode: FAST = "fast" SAFE = "safe" DEBUG = "debug"defprocess(data, mode: str):# 根据mode执行不同逻辑 ...process(data, mode=Mode.FAST)你的大脑阅读的是单词,不是布尔值。这能瞬间减轻认知负担。
⚠️ 注意:这里90%的人会踩坑有人会说“那我用注释解释布尔值不就行了?”——注释会过时,但类型安全不会。更何况,当你需要三个模式时,布尔值组合会指数级膨胀(
fast=True, safe=False, debug=True),而枚举只需要增加一个成员。
嵌套的条件判断,是可读性的债务。
糟糕的写法:
defsave(user):if user:if user.is_active:if user.has_permission: persist(user)这段代码的逻辑路径,你需要用眼睛“走迷宫”。
可读的写法:
defsave(user):ifnot user:returnifnot user.is_active:returnifnot user.has_permission:return persist(user)这就像外卖骑手等单:不符合条件就立刻退出,不堆积判断。扁平化的代码,就是可读的代码。你的眼睛不需要地图就能跟上执行路径。
内联逻辑看起来“聪明”,但读起来很费劲。
# ❌ 难以理解if request.user.profile.settings.preferences.theme.color == "dark": apply_dark_mode()这个链式访问,读一遍要花多久?
可读的写法:
# ✅ 引入语义化检查点preferences = request.user.profile.settings.preferencestheme_color = preferences.theme.colorif theme_color == "dark": apply_dark_mode()你没有增加代码行数,你增加的是清晰度。
_ 传递信号:“这个值存在,但我不用”Python 的 _ 不是装饰品,它是沟通工具。
# 遍历时忽略文件名,只处理子目录for _, filename in os.walk(directory): process(filename)或者在解包时:
user_id, _, email = get_user_data() # 中间的值是废弃字段它在告诉未来的读者:“是的,这里有个值。不,它不重要。”
这种坦诚,很重要。
如果你觉得需要写注释来解释某段代码在做什么——直接提取成一个函数。
糟糕的写法:
# 检查用户是否有权限访问仪表盘if user.is_authenticated and user.is_active andnot user.is_banned: show_dashboard()可读的写法:
defcan_access_dashboard(user):return ( user.is_authenticatedand user.is_activeandnot user.is_banned )if can_access_dashboard(user): show_dashboard()现在代码读起来像英语——注释变得多余了。
⚠️ 注意:函数命名要精确
check_user这种命名就是反面教材。命名应该回答“为什么”,而不是“是什么”。can_access_dashboard直接表达了意图。
字典用字符串键传递数据,含义藏在引号后面。
# ❌ 返回字典,结构不透明return {"min": min_value,"max": max_value,"avg": average}# 调用方:return_value["avg"] 还是 return_value["average"]?可读的替代方案:
from collections import namedtupleStats = namedtuple("Stats", ["min", "max", "avg"])defcalculate_stats(data):# ...计算逻辑return Stats(min_value, max_value, average)# 调用时stats = calculate_stats(data)print(stats.avg) # IDE 自动补全可用现在:
空白不是装饰——它是语法。
无间距版本:
validate_input(data)normalize(data)save(data)notify_user()log_event()这四个步骤是平铺的,读者不知道哪几行是同一阶段。
有间距版本:
validate_input(data)normalize(data)save(data)notify_user()log_event()每个空行,都是一个逻辑阶段的切换:
你的大脑能本能地理解这种分组。
魔法数字让代码撒谎。
if retries > 3: abort()3 是什么?为什么是 3?
可读的写法:
MAX_RETRIES = 3if retries > MAX_RETRIES: abort()这不只是为了常量——这是为了讲述数字背后的故事。当你读代码时,你看到的是“超过最大重试次数”,而不是一个孤立的数字。
⚠️ 注意:常量要放在正确的位置别把
MAX_RETRIES = 3写在函数内部。这会导致重复定义和维护困难。应该放在模块顶部或配置类中,让所有相关代码共享同一个定义。
elif(比你想象中更少)elif 隐藏了决策树的结构。
# 当状态增多时,这段代码会膨胀if status == "pending": handle_pending()elif status == "approved": handle_approved()elif status == "rejected": handle_rejected()当逻辑变复杂时,改用字典映射:
handlers = {"pending": handle_pending,"approved": handle_approved,"rejected": handle_rejected,}handlers[status]()现在行为是数据驱动的,不是条件堆砌。新增状态只需在字典中添加一行,而不是再加一个 elif。
这个模式尤其适合处理状态机、命令分发、RPC路由等场景。国内很多微服务框架的请求分发,底层就是这么做的。
类型会变,角色不会。
糟糕的写法:
list_of_users = []dict_of_settings = {}可读的写法:
users = []settings = {}或者更进一步,表达业务角色:
active_users = []feature_flags = {}你的变量名应该回答:“这个东西为什么存在?”
而不是“它是什么类型”。
技术债务不总是那些“大重构”。更多时候,它是每天写下一段自己都不想看的代码,然后告诉自己“以后再说”。
我见过太多团队在“可读性”上口惠而实不至——代码审查时只查逻辑错误,却放任认知负担一点点堆积。直到新人入职需要两周才能上手,直到线上故障定位需要三个小时。
好的代码,是写给下一个维护者的一封信。而这个维护者,很可能就是六个月后的你。
你今天写的每一行“明显的代码”,都是未来的你少掉的一根头发。
elif_ 表达忽略、命名元组替代字典、变量名表达角色而非类型你在代码审查中最常遇到的“可读性反模式”是什么?如果要在团队推行这10个技巧,你觉得哪个阻力最大?欢迎留言聊聊你的实战经验。

长按👇关注- 数据STUDIO -设为星标,干货速递
