簡體   English   中英

列表理解與發電機

[英]list comprehension with generator

我用generator來生成一些列表。 但是,它不像我預期的那樣工作。 我首先使用numgen1生成列表,但它無法正常工作。 然后我切換到numgen2,這可以給我正確的想法。 但是numgen1和numgen2基本相同(至少我認為),為什么它們表現得如此不同? 願任何人給我一些解釋嗎?

def numgen1(start, end, delta):
    curr=start 
    while curr[1] < end[1] or curr[2]<end[2]:
        yield curr
        curr[2] += delta


print 'Output1: ', [ i for i in numgen1([1,1,1],[1,1,5],1)]

def numgen2(start, end, delta):
    curr=start 
    while curr[1] < end[1] or curr[2]<end[2]:
        yield [curr[0], curr[1], curr[2]]
        curr[2] += delta


print 'Output2: ', [ i for i in numgen2([1,1,1],[1,1,5],1)]

這是輸出。

Output1:  [[1, 1, 5], [1, 1, 5], [1, 1, 5], [1, 1, 5]]
Output2:  [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4]]

跟進問題:

在閱讀unutbu的答案之后,我又寫了一個用於測試unutbu所說的生成器。 但是發電機不像unutbu那樣表現。 我對生成器是否產生指針或值的副本感到困惑。

def numgen3(start, end, delta):
    curr=start 
    while curr<end:
        yield curr
        curr += delta

print list(numgen3(1,10,1))

這是輸出。 [1,2,3,4,5,6,7,8,9]

這次我嘗試生成一些數字而不是一些列表。 但為什么不是列表9中的所有元素? 我沒有創建一個新的數字,我只是產生相同的數字(curr)。 我期望numgen3的結果應該類似於numgen1的結果。

curr是一個清單。 curr[2] += delta正在就地修改列表。

當你產生curr ,你會一遍又一遍地產生相同的列表。 當您打印Output1您會看到同一列表被多次打印。

當您產生[curr[0], curr[1], curr[2]]您將生成一個新列表。 因此,當您打印Output2 ,您會看到不同的值。


注意修改curr如何影響result 所有項目 ,因為result是一個包含3個項目的列表,每個項目都是相同的列表curr

curr = [0,0,0]
result = [curr for i in range(3)]
print(result)
# [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

curr[2] = 100
print(result)
# [[0, 0, 100], [0, 0, 100], [0, 0, 100]]

您可以通過產生list(curr)來“修復” numgen1 ,因為list(curr)返回一個新的列表,其中包含與curr相同的元素(即“淺拷貝”):

def numgen1(start, end, delta):
    curr=start 
    while curr[1] < end[1] or curr[2]<end[2]:
        yield list(curr)
        curr[2] += delta

print 'Output1: ', [ i for i in numgen1([1,1,1],[1,1,5],1)]

產量

Output1:  [[1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 1, 4]]

關於numgen3

def numgen3(start, end, delta):
    curr=start 
    while curr<end:
        yield curr
        curr += delta

print list(numgen3(1,10,1))

它有助於在可變值和不可變值之間進行精神區分。 列表是可變的,諸如ints類的數字是不可變的。

列表是容器。 您可以在不更改對容器的引用的情況下改變其內容。 因此curr是一個列表, curr[2] += delta改變索引2處的內容 ,但yield curr產生相同的列表。

numgen3curr是一個不可變的int curr += deltacurr分配給新的immutable int 它不再引用同一個對象。 yield curr產生該值。 這些不同的值在列表推導中累積,因此您可以看到包含不同值的結果。


下面是什么意思修改就地列表另一個角度來看:修改在原地做,如果列表的內容發生變化,而列表中的內存地址本身並沒有改變。

id(obj)返回對象obj的內存地址。 請注意,修改curr[2]不會更改currid

In [162]: curr = [0,0,0]

In [163]: id(curr)
Out[163]: 196192940

In [164]: curr[2] += 1

In [165]: curr
Out[165]: [0, 0, 1]

In [166]: id(curr)
Out[166]: 196192940

將其與增加分配給int的變量時發生的情況進行比較:

In [191]: curr = 1

In [192]: id(curr)
Out[192]: 150597808

In [193]: curr += 1

In [194]: id(curr)
Out[194]: 150597796

這里, curr沒有就地修改。 curr被簡單地重定向以在新的內存地址處引用新值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM