【发布时间】:2022-08-19 04:39:51
【问题描述】:
我在 3.8 的 REPL 中尝试了这段代码:
>>> a = list(range(10))
>>> a[:] = (i for i in a for _ in range(2))
我们根据来自生成器的元素分配a 的元素,并且该生成器正在迭代a,我们甚至没有元素的一一对应关系。这看起来很像modifying the list while iterating over it,所以我预计这会以某种方式表现不佳。
但相反,它完全按照天真的期望工作:
>>> a
[0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9]
经过片刻的思考,Python 似乎必须在实际执行分配之前制作某种临时副本。毕竟,插入的切片可能与替换的切片大小不同(只要它不是扩展切片),这需要从切片之后移动元素;如果不评估生成器,就无法知道将它们移动多远。
然而,很容易想象一个仍然会遇到问题的实现。例如:将切片后的元素复制到一个临时的;从切片的开头开始标记为未使用;按照通常的.append 逻辑从生成器中附加元素;最后.extend 是临时的。 (当然,这对扩展切片不起作用,但扩展切片无论如何都不能调整列表的大小。)那实现,我们的示例将立即命中IndexError,因为该列表将在生成器开始使用之前被清除。
那么:实际行为是否可靠/有保证?它是特定于版本的吗? Python 究竟是如何实现切片赋值的?
标签: python list language-lawyer generator