You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅实现惰性求值的all()校验?替代重复yield生成器

优雅实现惰性求值的布尔校验(告别重复yield的生成器)

你遇到的这个问题我太懂了——用all(lst)的时候,数组里的所有表达式(不管是函数调用还是属性访问)会被一次性全部执行,完全达不到“遇到第一个False就停”的短路效果;而手写生成器挨个写yield又太啰嗦,重复的关键字堆在一起既不优雅,还违反了DRY(Don't Repeat Yourself)原则。

下面给你几个更清爽的解决方案,完美满足按需计算+短路求值的需求:

方案1:生成器表达式+Lambda包装(最简洁)

把每个需要延迟计算的表达式用lambda:包装成无参函数,然后放进生成器表达式里。all()迭代的时候才会调用这些lambda,而且一旦遇到False就立刻停止,后面的表达式根本不会执行:

all(
    func() for func in (
        lambda: 1,          # 直接返回值的表达式
        lambda: a(),        # 函数调用
        lambda: obj.prop,   # 对象属性访问
        # ... 其他需要校验的表达式
        lambda: z()
    )
)

这种写法只需要给每个表达式加个lambda:前缀,没有冗余的代码,可读性也很强。

方案2:自定义惰性求值工具函数(复用性更强)

如果你经常需要做这类校验,可以封装一个小工具函数,把传入的lambda表达式逐个惰性返回:

def lazy_check(*checks):
    for check in checks:
        yield check()

# 使用时直接传包装好的表达式
all(lazy_check(
    lambda: 1,
    lambda: a(),
    lambda: obj.prop,
    # ...
    lambda: z()
))

这个工具函数可以复用在任何需要惰性求值的场景,代码语义更清晰,一眼就能看出是在做延迟校验。

方案3:针对纯函数调用的简化版(可选)

如果你的校验项全是函数调用(没有属性访问这类表达式),可以用itertools.starmap来简化,把函数和参数分开传递:

from itertools import starmap

all(starmap(func, args) for func, args in (
    (lambda: 1, ()),  # 无参函数传空元组
    (a, ()),
    (b, (2, 3)),      # 如果是带参函数b(2,3)就这么写
    # ...
    (z, ())
))

不过这个方案对属性访问的场景不太友好,适合纯函数调用的场景。

核心原理

不管用哪种方案,本质都是把需要计算的表达式转换成“可延迟执行的对象”,然后利用all()函数的短路特性——一旦迭代到第一个返回False的元素,就立刻终止迭代,后面的延迟对象根本不会被执行,完美实现了“按需计算”的需求。

内容的提问来源于stack exchange,提问作者trampampam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:12:45