[英]Why can't I change the list I'm iterating from when using yield
我在這里有一些可重現的代碼:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, a)
打印出:
[1, 2, 3, 0]
[1, 2, 3, 0]
[2, 3, 0, 1]
[2, 3, 0, 1]
[3, 0, 1, 2]
[3, 0, 1, 2]
[0, 1, 2, 3]
[0, 1, 2, 3]
這是我的預期,但當我做list(test())
我得到:
[(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3]),
(2, [0, 1, 2, 3]),
(3, [0, 1, 2, 3])]
為什么會這樣,我該怎么做才能解決這個問題?
因為你總是返回(i,a)
現在a
是對列表的引用 。 因此,您不斷返回對同一列表的引用 。 這是沒有問題的print
語句,因為它立即打印的狀態, a
在那一刻 。
您可以返回列表的副本 ,例如:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, list(a))
你每次都會產生相同的列表,所以調用者的列表只有一堆對該列表的引用,每次調用時都會更新。 當您屈服時,您需要復制列表:
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, a[:])
顯式更好的隱含:
import copy
def test():
a = [0, 1, 2, 3]
for _ in range(len(a)):
a.append(a.pop(0))
for i in range(2,4):
print(a)
yield(i, copy.copy(a))
最后得到一個元組列表,元組的第二個元素是相同的列表 。 您可能會注意到它們都等同於生成器生成的最后一個列表,而不是第一個列表; 列表正在改變,但元組都引用了同一個。
為清楚起見,請嘗試修改其中一個列表。 例如,如果你運行l[0][1].append(4)
,你就會得到
[(2, [0, 1, 2, 3, 4]),
(3, [0, 1, 2, 3, 4]),
(2, [0, 1, 2, 3, 4]),
(3, [0, 1, 2, 3, 4]),
(2, [0, 1, 2, 3, 4]),
(3, [0, 1, 2, 3, 4]),
(2, [0, 1, 2, 3, 4]),
(3, [0, 1, 2, 3, 4])]
所有列表都附加了4個,因為只有一個列表。
如果要返回副本,有幾種方法。 您可以yield (i, a[:])
(使用切片表示法獲取副本), yield (i, list(a))
(使用list
構造函數獲取副本)或yield (i, copy.copy(a))
(使用copy
模塊)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.