名字是写给下一个读代码的人的,那个人半年后可能是你自己。
常见的数据配常见的名字:个数叫 count,合计叫 total,下标叫 i。
比「好名字」更重要的是一致——同一类东西,全书用一个叫法。
这是第 2 章的专题,教材把它放在最后一节,因为前面所有例子里的名字都出现了。 2.3 讲过命名的三条硬规矩(字母开头、不含符号、不撞关键字)。这一篇补的是软规矩。 软规矩不遵守代码也能跑——这正是它容易被忽略的原因。
一、名字是写给人看的,编译器不看
s1、s2、t、m、x 这些名字,机器一样能跑。它只关心「这是同一个变量」。
受苦的是读的人。读到 avg = t / m 的时候,你得往上翻十几行才知道 t 是总分、m 是人数。
教材这一节的重点其实不在那张表,在「一致」两个字。
名字起得一般但前后一致,比起得漂亮但换一个说法就换一个名字强得多。
理由很实在:读代码时人是靠「形状」认东西的。同一个概念总是同一个词,眼睛扫过去就能连起来; 换个说法,就得重新判断一次。
二、一张对照表:常见的数据配常见的名字
下面这张表不是标准,是惯例。用惯例的好处是别人不用学你的习惯。
| 装的东西 | 常用名字 | 别写成 |
|---|---|---|
| 个数 | count |
n1、a |
| 合计 | total |
t |
| 平均值 | average |
m |
| 最大值、最小值 | max_value、min_value |
max(和函数重名) |
| 下标 | i、index |
x |
| 临时存放 | temp |
tmp2、tmp3 |
| 开关标志 | found、is_ready |
flag(说不清是什么标志) |
最后两行值得停一下。temp 短命,用完就扔,叫 temp 最省事;
但 tmp2、tmp3 一多,就没人记得哪个是哪个了。
flag 的问题不是难看,是没信息。if flag: 读完不知道在判断什么,而 if found: 一眼就懂。
名字要把「是什么」写进去,不是把「是个布尔值」写进去。
还有 max 那一行:拿内置函数名当变量名,后面再想调 max() 就调不到了。
这类错在 Python 里不报错,只是行为突然变了。
三、拿一个检查器,把候选名字过一遍
演示里写了个小检查器,扫九个候选名字。三个通过:score、max_score、cnt。
六个被挡下来,但它们不是一类问题。前三条是语法,后两条是约定。
| 挡下来的原因 | 属于 | 不改会怎样 |
|---|---|---|
数字开头(2nd_score) |
语法 | 直接报错,跑不起来 |
有非法字符(max-score) |
语法 | 直接报错,跑不起来 |
是关键字(for) |
语法 | 直接报错,跑不起来 |
l、O、I 单字母 |
约定 | 和数字 1、0 长得像,看错人 |
| 名字太长 | 约定 | 能跑,但一行放不下,读着累 |
演示最后那句还提了「太短」这条约定,只是这一批候选没撞上——最短的是 cnt,三个字母还说得过去。
名字叫 a 的时候它才会响。
这五行合起来说明一件事:语法只挡前三行,后两行没人替你挡。
四、「能跑」和「好读」之间隔着一张检查表
语法错误编译器会喊你,约定不合没人喊。所以后者只能靠两样东西:自己定的规矩,和能自动跑的检查。
检查器可以很简单:长度在 3 到 24 之间、只含字母数字下划线、不在关键字表里、不是 l/O/I。
二十行代码,能挡掉大部分低级问题。
再往上一步是团队约定:这份代码里「个数」永远叫 count,永远不叫 num、cnt、n。
这条约定写进文档,比任何一次代码评审都省事。
这也是本书后面所有例子的写法依据——看后面章节的代码时,先认名字,往往比先看逻辑更快读懂。
五、这一章收个尾
第 2 章从「数据是什么」讲到「数据怎么摆」,再到「数据叫什么」。三件事凑齐了,才谈得上写算法。 回顾一下这条线:值有类型(2.1),值装进变量(2.2、2.3),同类的值排成数组(2.4、 2.5),数组摞成表格、字符排成字符串(2.6)。 下一章换一个维度:同样一堆数据,摆放的方式不同,取用的代价能差上千倍。那就是数据结构。
六、动手 Demo:九个候选名字,过一遍检查器
先看一张「什么数据配什么名字」的对照表。 再用一个二十来行的检查器,把九个候选名字逐个过一遍,看它挡下哪几个、为什么。
import keyword
def check(name):
if not name[0].isalpha():
return '不过:数字开头'
if not all(c.isalnum() or c == '_' for c in name):
return '不过:有非法字符'
if keyword.iskeyword(name):
return '不过:是关键字'
if name in ('l', 'O', 'I'):
return '不过:l/O/I 单字母,和数字像'
if len(name) > 24:
return '不过:太长'
return '通过'
for n in ('score', 'max_score', '2nd_score', 'max-score',
'for', 'cnt', 'l', 'O', 'score_of_the_student_in_class'):
print(n, ' -> ', check(n))
实跑输出:
--------------------------------------------------------------------
常用变量命名:一张对照表和一个检查器
--------------------------------------------------------------------
① 数据是什么,名字就用什么
--------------------------------------------------------------------
| 装的东西 | 常用名字 | 别写成 |
|---|---|---|
| 个数 | count | n1、a |
| 合计 | total / sum | t |
| 平均值 | average / avg | m |
| 最大值、最小值 | max_value / min_value | max(和函数重名) |
| 下标 | i / index | x |
| 临时存放 | temp | tmp2、tmp3 |
| 开关标志 | found / is_ready | flag(说不清是什么标志) |
这些名字不神圣,但用得一致,别人扫一眼就知道这一行在算什么。
教材这一节的重点不在表,在「一致」两个字。
② 拿一个检查器,扫一批候选名字
--------------------------------------------------------------------
score -> 通过
max_score -> 通过
2nd_score -> 不过:数字开头
max-score -> 不过:有非法字符
for -> 不过:是关键字
cnt -> 通过
l -> 不过:l/O/I 单字母,和数字像
O -> 不过:l/O/I 单字母,和数字像
score_of_the_student_in_class -> 不过:太长
后三条(l/O/I、太长、太短)是约定,不是语法。
语法只管前三条——所以「能跑」和「好读」之间,永远隔着这么一张检查表。
①检查器里前三条是语法(数字开头、非法字符、关键字),后两条是约定(单字母、太长)。
顺序不能反:语法先挡,约定后挡。
②keyword.iskeyword 是标准库给的,不用自己维护关键字表。
③输出里 cnt 是通过的——它不违规,只是不如 count 清楚。
检查器只能挡「不能跑」和「明显坑人」,挡不住「不够好」。
④最后那个长名字被挡是因为超过 24 个字符。这个上限是随手定的,换成 32 结论也一样,别当成标准。
30 秒实验
- 把
check里的 24 改成 32,看那个长名字还能不能通过。 - 给检查器加一条:「不能和内置函数重名」(
max、sum、list),用dir(__builtins__)试。 - 翻一翻你自己写过的代码,找出三个名字,看看过不过得了这个检查器。
常见误区
- 「名字起什么都行,反正能跑。」能跑,但读的人要多花几倍时间,包括三个月后的你。
- 「名字越长越清楚。」超过二十多个字符,一行放不下,反而难读。清楚靠选词,不靠堆词。
- 「
flag是标准写法。」它只说了「这是个开关」,没说「是什么开关」。用found、is_ready。
自测三问(点开对答案)
1. 命名的硬规矩和软规矩各是什么? —— 硬规矩(语法):字母开头、只含字母数字下划线、不撞关键字。软规矩是约定,靠人和检查器。 2. 为什么不该用 `max` 当变量名? —— 它是内置函数名。覆盖之后再用 `max()` 就调不到了,而且不报错,只是行为变了。 3. 为什么说「一致」比「好名字」更重要? —— 读代码靠形状认东西。同一概念总是同一个词,眼睛能直接连起来;不断换说法就得重新判断。第 2 章到此结束。 下一章讲同样一堆数据,摆放方式不同,取用代价差上千倍——从堆栈、队列开始,到链表、树、图。
- ☐ (本篇完,下一篇 3.1 为什么要学数据结构)