使用yield将列表生成函数转为生成器时遇输出异常求助
问题:yield迭代器输出不符合预期的原因
我尝试用yield将for循环转换为迭代器,但多次尝试都失败了,输出结果和预期不符。以下是我的尝试代码及输出:
错误的yield版本代码
def iteration_order(dimensions): for dim in range(dimensions): order = [0, dim, 0] yield order for j in range(6): sgn = 1 if j % 2 == 0 else -1 idx = j % 3 for _ in range(dim if j < 5 else dim-1): order[idx] += sgn yield order
输出结果
print(list(iteration_order(2))) >>> [[0, 0, 0], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1], [0, 1, 1]]
可正常运行的非yield版本代码
def iteration_order(dimensions): full_order = [] for dim in range(dimensions): order = [[0, dim, 0]] for j in range(6): sgn = 1 if j % 2 == 0 else -1 idx = j % 3 for _ in range(dim if j < 5 else dim-1): nxt = list(order[-1]) nxt[idx] += sgn order.append(nxt) full_order.extend(order) return full_order
输出结果
print(iteration_order(2)) >>> [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
问题根源
核心问题出在可变对象的引用特性上:
- 在yield版本中,你始终在修改同一个列表对象
order,并且反复yield这个对象的引用。因为列表是可变类型,所有被yield出去的元素其实都是指向同一个内存地址的引用。后续对order的每一次修改,都会同步影响所有已经被yield出去的列表内容,最终所有元素都会变成最后一次修改后的结果。 - 而在正确的非yield版本中,每次新增元素时都会执行
nxt = list(order[-1]),这相当于复制了前一个列表的内容,创建了一个全新的列表对象。因此order列表中的每个元素都是独立的,不会互相干扰。
修正后的yield版本代码
只需要在每次yield时,生成当前order的副本即可,比如使用list(order)或者order.copy()来创建新列表:
def iteration_order(dimensions): for dim in range(dimensions): order = [0, dim, 0] yield list(order) # 生成副本 for j in range(6): sgn = 1 if j % 2 == 0 else -1 idx = j % 3 for _ in range(dim if j < 5 else dim-1): order[idx] += sgn yield list(order) # 生成副本
修正后的输出
print(list(iteration_order(2))) >>> [[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0], [1, 0, 1], [0, 0, 1], [0, 1, 1]]
内容的提问来源于stack exchange,提问作者oskros
相关产品推荐
相关产品推荐

