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 行逻辑浓缩成了一个声明式的表达式。一旦你习惯了这种“描述我要什么”而非“告诉机器怎么做”的思维,就会发现它比传统循环更清晰、更不容易出错。

posted @ 2026-10-01 18:12  立体风  阅读(4)  评论(0)    收藏  举报