Python 3.7中如何在列表推导式内实现列表迭代更新
解决列表推导式中迭代更新状态的问题
我懂你的困扰:列表推导式写起来清爽,但默认没法像for循环那样逐步更新变量——你之前的尝试里,每一步都在复用初始的viruses列表,自然得不到正确的迭代结果。其实我们可以借助itertools.accumulate来实现状态的链式传递,完美适配列表推导式的写法。
问题根源
你写的不可行列表推导式,本质上是一次性生成了timesteps个独立结果,每一次计算都基于原始的viruses,完全没有保留上一步的变异状态。而for循环的核心是每一步都用前一次的输出作为下一次的输入,这正是列表推导式默认做不到的。
解决方案:用itertools.accumulate传递状态
itertools.accumulate的作用就是迭代地应用一个函数,把前一次的输出作为下一次的输入,刚好能模拟for循环里的状态更新。我们可以用它生成每一步的病毒列表状态,再用列表推导式收集每个状态的长度。
先看改造后的代码:
from itertools import accumulate def simulate(viruses, mortalityProb, mutationProb, maxReproductionProb, maxPopulation, timesteps = 500): # 用accumulate生成所有迭代状态:初始状态 + timesteps次变异后的状态 all_virus_states = accumulate( # 构造包含初始状态 + timesteps个占位符的可迭代对象 [viruses] + [None] * timesteps, # 定义单次迭代逻辑:接收前一次状态,返回下一次状态 lambda prev_state, _: reproduce( kill(prev_state, mortalityProb), mutationProb, reproductionProbability(prev_state, maxReproductionProb, maxPopulation) ) ) # 用列表推导式收集每个状态的长度 return [len(state) for state in all_virus_states]
代码解释
accumulate的参数逻辑:- 第一个参数是一个可迭代对象,我们放了初始的
viruses加上timesteps个None(占位符,仅用来触发timesteps次迭代,实际不会用到这些值)。 - 第二个参数是lambda函数,它接收两个值:
prev_state(上一轮的病毒列表状态)和占位符_(我们直接忽略),返回经过kill和reproduce处理后的新状态。
- 第一个参数是一个可迭代对象,我们放了初始的
状态链式传递:
- 第一次迭代时,
prev_state是初始的viruses,计算出第一个变异后的状态; - 第二次迭代时,
prev_state自动变成上一步的变异结果,以此类推,完全复刻了原for循环的迭代逻辑。
- 第一次迭代时,
结果收集:
- 最后用列表推导式遍历
all_virus_states,收集每个状态的长度,得到和原可行代码完全一致的结果。
- 最后用列表推导式遍历
为什么这比原列表推导式可行?
原列表推导式是并行计算所有元素,而accumulate是串行迭代,每一步都依赖前一步的结果,完美解决了状态连续更新的问题。
内容的提问来源于stack exchange,提问作者Kaas Broodje
相关产品推荐
相关产品推荐

