Python中创建生成器工厂时内部生成器状态异常问题
生成器工厂内部状态异常:原因与紧凑实现方案
问题根源
Python生成器表达式采用延迟求值,且内部变量是引用捕获而非值捕获:你定义的内部生成器并没有保存循环变量b的当前值,只是保存了对b的引用。当外部工厂生成器推进时,b的值被更新,所有之前创建的内部生成器再调用时,都会使用b的最新值,导致状态混乱。
比如你的测试代码中,g0生成器引用的b会在g1被创建时被更新为20,因此后续next(g0)会计算pow(20,3),而非预期的pow(10,3)。
而转为列表能得到正确结果,是因为列表推导会在b更新前就一次性迭代完内部生成器的所有元素,此时b还未被修改。
紧凑解决方案(无需自定义类)
方案1:用lambda默认参数绑定变量值
利用lambda默认参数在定义时立即捕获当前b的值,避免后续引用更新后的变量:
import itertools as it gen_factory = ((lambda b=b: (pow(b, a) for a in it.count(1)))() for b in it.count(10, 10))
验证代码:
g0 = next(gen_factory) next(g0) # 10 next(g0) # 100 g1 = next(gen_factory) next(g1) # 20 next(g0) # 1000(符合预期,不受g1影响)
有限场景适配:
finite_gen_factory = ((lambda b=b: (pow(b, a) for a in (1,2,3)))() for b in (10,20,30)) g0 = next(finite_gen_factory) g1 = next(finite_gen_factory) next(g0) # 10(正确)
方案2:通过functools.partial固定参数
用partial把pow的底数参数固定为当前b的值,同样需要lambda包裹避免引用问题:
import itertools as it from functools import partial gen_factory = ((lambda b=b: (partial(pow, b)(a) for a in it.count(1)))() for b in it.count(10, 10))
该方案和方案1逻辑一致,适合参数较多或需要复用绑定逻辑的场景。
关于it.tee的说明
it.tee用于复制同一个生成器的多个迭代器,无法解决变量引用捕获的问题,因此不适用你的场景。
内容的提问来源于stack exchange,提问作者njp
相关产品推荐
相关产品推荐

