python 声明式语法
def summary(self):
p = sum(1 for _, ok, _ in self.rows if ok is True)
f = sum(1 for _, ok, _ in self.rows if ok is False)
s = sum(1 for _, ok, _ in self.rows if ok is None)
return p, f, s
其中: p = sum(1 for _, ok, _ in self.rows if ok is True)在干什么?
这行代码确实把很多 Python 语法“压缩”在了一起。我们把它像剥洋葱一样,从外到内拆解成 4 个步骤,你就完全明白了。
1. 最外层:sum(...) 在干什么?
sum() 的作用就是把括号里产生的所有数字加起来。
在这里,它加的不是列表里的原始数据,而是后面那个生成器按需吐出来的 1。每吐出一个 1,sum 就累加一次。所以,吐出多少个 1,最终结果就是多少。这就实现了“计数”的功能。
2. 中间层:生成器表达式 (1 for ... if ...)
注意这里是小括号 () 而不是方括号 []。
- 如果是
[1 for ...],会立刻在内存中创建一个完整的列表(比如[1, 1, 1]),然后再传给sum。 - 使用
(1 for ...)是生成器表达式。它不会创建列表,而是像一个“懒汉工厂”,sum要一个,它才现场算一个、给一个。对于海量数据,这能节省大量内存。
3. 循环与解包:for _, ok, _ in self.rows
假设 self.rows 里存的是这样的数据:
[("登录测试", True, "耗时2s"), ("支付测试", False, "超时"), ("跳过项", None, "")]
当循环走到第一项 ("登录测试", True, "耗时2s") 时:
_接收"登录测试"(下划线_是 Python 的强约定,表示“这个值我不需要,直接丢弃”)ok接收True(这是我们唯一关心的状态值)_接收"耗时2s"(同样丢弃)
通过这种元组解包,我们不需要写 row[1] 这样难懂的索引,直接用有意义的变量名 ok 拿到了第二个元素。
4. 过滤条件:if ok is True
这是整个表达式的灵魂。生成器只有在这个条件满足时,才会吐出 1。
⚠️ 为什么必须用 is True,而不能用 if ok?
因为 ok 有三种状态:True、False、None。
- 如果写
if ok:,那么True和非空字符串都会被当作真值,可能导致误判。 is True是严格的身份比较,它只认 Python 内置的那个唯一的True对象。False和None都会被精准排除。
🔄 完整执行流程模拟
让我们跟着解释器走一遍:
| self.rows 中的项 | 解包后 ok 的值 | ok is True ? |
生成器动作 | sum 累计值 |
|---|---|---|---|---|
("登录", True, "...") |
True |
✅ 是 | 吐出 1 |
1 |
("支付", False, "...") |
False |
❌ 否 | 跳过,不吐 | 1 |
("跳过", None, "") |
None |
❌ 否 | 跳过,不吐 | 1 |
最终 sum 只收到了一个 1,返回结果 1。
💡 等价的传统写法
如果你还是觉得一行太绕,它完全等价于下面这段传统代码:
p = 0
for name, ok, detail in self.rows:
if ok is True:
p = p + 1
原代码只是把这 4 行逻辑浓缩成了一个声明式的表达式。一旦你习惯了这种“描述我要什么”而非“告诉机器怎么做”的思维,就会发现它比传统循环更清晰、更不容易出错。

浙公网安备 33010602011771号