2013-01-01 18 views
3

有人可以提供關於這兩個Python操作之間在修改列表方面的區別的簡明解釋嗎?當python列表迭代是並且不是引用時

demo = ["a", "b", "c"] 

for d in demo: 
    d = "" 

print demo 
#output: ['a', 'b', 'c'] 

for c in range(len(demo)): 
    demo[c] = "" 

print demo 
#output: ['', '', ''] 

換句話說,爲什麼第一次迭代沒有修改列表?謝謝!

+1

[在Python中不允許修改列表迭代器?](http://stackoverflow.com/questions/9414399/modifying-a-list-iterator-in-python-not-allowed) –

回答

4

循環變量d總是在迭代的對象的元素的引用。這個問題不是什麼時候或何時不是一個參考。這是關於您使用循環執行的賦值操作。

在第一個示例中,您重新綁定了對象中元素的原始引用,並引用了另一個空字符串。這意味着您實際上不會對做任何事情。您只需爲該符號分配一個新的參考。

在第二個示例中,您正在執行索引操作併爲該索引處的值分配新的引用。 demo保持相同的引用,並且您正在替換容器中的值。
分配確實是等價的:demo.__setitem__(c, "")

a = 'foo' 
id(a) # 4313267976 
a = 'bar' 
id(a) # 4313268016 

l = ['foo'] 
id(l) # 4328132552 
l[0] = 'bar' 
id(l) # 4328132552 

請注意,在第一個例子中,對象ID已經改變。它是對新對象的引用。在第二個,我們索引到列表中並替換容器中的值,但該列表仍然是同一個對象。

4

在第一個示例中,變量d可以被認爲是列表中元素的副本。在做d = ""時,你基本上是修改了列表中任何內容的副本,這自然不會改變列表。

在第二個示例中,通過執行range(len(demo))並索引列表中的元素,可以直接訪問和更改列表中的元素。因此,做demo[c]會修改列表。

如果您確實想從循環內部直接修改Python列表,您可以複製列表並對其進行操作,或者最好使用列表理解。

所以:

>>> demo = ["a", "b", "c"] 
>>> test = ["" for item in demo] 
>>> print test 
["", "", ""] 

>>> demo2 = [1, 5, 2, 4] 
>>> test = [item for item in demo if item > 3] 
>>> print test 
[5, 4] 
1

當你做d = <something>你正在使變量d參考<something>。這樣,您可以使用d,就好像它是<something>一樣。但是,如果您執行d = <something else>,則d現在指向<something else>,而不再是<something>=符號用作賦值運算符)。在demo[c] = <something else>的情況下,您將<something else>分配給列表中的(c+1)th項目。

有一點要注意,然而,就是如果該項目d有要調用自修改的方法,你可以做

for d in demo: 
    d.<some method>() 
由於該表 demo包含那些對象

(或引用的對象,我不記得),因此如果這些對象被修改,列表也被修改。