当python列表迭代是并且不是引用时

时间:2013-01-01 19:49:25

标签: python reference

有人可以就修改列表方面的这两个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: ['', '', '']

换句话说,为什么第一次迭代不会修改列表?谢谢!

3 个答案:

答案 0 :(得分: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 :(得分: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已更改。它是对新对象的引用。在第二个中,我们索引到列表并替换容器中的值,但列表仍然是同一个对象。

答案 2 :(得分: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包含那些对象(或对象的引用,我不记得了),因此如果修改了这些对象,列表也会被修改。