2017-08-01 88 views
6

當從我遍歷名單上有一些可重複的代碼在這裏:爲什麼我不能改變使用產量

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])] 

爲什麼是這樣的話,我能做些什麼來解決它?

+4

因爲你總是返回一個*引用*到列表中,而不是* *副本*的列表。 –

+0

您僅打印「a」,但返回(i,a)。 –

+0

@AndreyLukyanenko:我認爲OP對列表的*內容*感到困惑:所有收益率都有相同的列表。 –

回答

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))
3

你產生每一次相同的列表,所以調用者的名單只是有一堆到該列表的引用,每次調用時都會更新。你需要做的名單的副本,當你得到:

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

明確更好隱:

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)) 
1

你最終的元組的列表,元組的第二個元素是相同列表。你可能會注意到它們和發電機的最後一個列表相等,而不是第一個;該列表正在改變,但元組都具有相同的引用。

爲了清楚起見,請嘗試修改其中一個列表。例如,如果運行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, list(a))(使用list構造函數獲取副本)或yield (i, copy.copy(a))(使用copy模塊)。

相關問題