缩进地狱
代码一层层往右缩,深到人眼跟丢每一层在保护什么。
它是什么
缩进地狱 是一种阅读上的困境,不是一种报错。选择、循环 一层套一层,每一层都再往右 缩进,页面右侧堆起一座台阶。程序可以正常运行,人却已经看不清每一层在问什么,也看不清某个 else 配的是哪一个 if。
if ready:
if charged:
if not raining:
print("出发")这三层在保护同一件事:准备好了,并且充上电,并且没有下雨。层次本身没有增加新的问题,只是把一个路口拆成了三问。能合成一个条件时,深缩进往往是多余的。
名字从哪来
英语讨论里,这种往右排成箭头的深嵌套常被称作 arrow code。杰夫·阿特伍德(Jeff Atwood)在 2006 年用这个名字讨论过:如何把箭头摊平,而不是让每一层条件再往里缩一截。「缩进地狱」说的是同一现象,强调的是人的阅读成本,不是机器因此算得更慢。
另一件容易混在一起的事是回调地狱,英语里也常叫 pyramid of doom。那是异步操作一层层把后续工作交回去,问题在时间顺序,不在左边空了多少格。
它怎么工作
每多一层 代码嵌套,读者就要同时记住:外层条件仍然成立,现在才轮到内层。两三层还容易跟住。再深,检查「这一支在什么前提下才会走到」就得靠数空格,而不是靠句子的意思。
有两条常见的出路,选哪一条取决于后来还需不需要分辨「是哪一条没通过」。
几条必须同时成立的判断,可以收成一个条件,见 逻辑嵌套。上面的三层就可以写成 ready and charged and not raining,选择结构只剩一个路口。
内层若是一整段独立的工作,就收成 函数。外层只留下「在什么前提下调用它」,函数内部再处理自己的层次。调用没有把空白继续往右推。
生活里在哪里
规章写成「若甲,则若乙,则若丙,才可以办理」,读到第三层时,人已经忘了第一层的前提还在生效。实验步骤若也这样套,检查的人会漏掉某一层是否真的做过。大纲的条目缩进太深,同样让人找不到自己在哪一节。文字里这只是难读;在 Python 里,难读的那一层缩进仍然是语法,走错一层,执行的就是另一条规则。
和相近概念的差别
缩进 是标明「谁属于谁」的语法。缩进地狱是缩进深到人跟丢,不是缩进写错。写错会无法运行,或在能运行时悄悄改掉某一句的归属;写对但太深,解释器照样执行。
浅的代码嵌套常常是必要的:先分大类,再在大类里面分小类。不是用了嵌套就算进了地狱。逻辑嵌套减少的是不必要的层次,不是取消一切判断。
常见误会
误会 1:缩进地狱是语法错误。
不是。解释器不因为「太深」而拒绝执行。能运行,不等于人还读得懂每一层在保护什么。
误会 2:只要嵌套了,就是缩进地狱。
两层把「先问这一类,再问这一类里面的差别」写清楚,往往正是问题所要的结构。困境出在深到必须数空格才能配对的时候。
误会 3:把所有嵌套都压成一行 and 一定更好。
压平之后,失败的原因合成了一个真假。若后面还要分别处理「没准备好」「没充电」「在下雨」,浅的代码嵌套比一个合取更清楚。摊平是为了让层次对应真实的问题,不是为了让左边看起来整齐。
想知道更多
- 书:布鲁克希尔《计算机科学概论》
- 书:艾伦·唐尼《像计算机科学家一样思考Python(第2版)》
- 书:埃里克·马瑟斯《Python编程:从入门到实践(第3版)》
未登录时不会保存学习进度