关于python中的迭代器

时间:2013-04-17 00:47:37

标签: python loops iterator

如果我有以下列表:

a = [1, 2, 3]

我运行以下代码:

for x in a:
  x += 1

这似乎不会更改列表a

但是,如果我执行以下操作:

for i in range(0, len(a)):
  a[i] += 1

这将修改'a'的内容。

所以我猜xa[i]以不同的方式引用a的元素。究竟是什么导致了这种差异?它们如何引用a

的元素

4 个答案:

答案 0 :(得分:5)

当您遍历列表时,依次会产生每个元素。但是,有不同种类的对象。 mutable immutable 。当你做类似的事情时:

a += 1

使用不可变对象,它大致翻译为:

a = a + 1

现在,在这种情况下,您可以通过a获取对象引用,为其添加1以创建新对象。然后,为该新对象分配名称a。请注意,如果我们在迭代时执行此操作,我们根本不会触及列表 - 我们只会继续创建新对象并将它们分配给名称a

对于可变对象,这是不同的。然后a += 1实际上将对象更改为。因此,列表将看到更改,因为它所持有的对象已更改(已更改)。 (对于不可变对象,列表中包含的对象未被更改,因为它不可能)。有关详细信息,请参阅this question

当你按索引进行迭代时,这也会让你更清楚一下发生了什么。你构造一个新的整数,然后把它放在列表中(忘记之前那个插槽中的内容)。

答案 1 :(得分:3)

当你说,

for x in [1,2,3]:
    x+=1

您说,暂时将x保存为变量,并为该临时保存添加一个。当你进入下一次迭代时,垃圾人会破坏该变量,因为它是暂时的。 x不是列表中的位置。它是列表中该点的值。

编辑:当我说它被删除时,我不清楚我的话。会发生的是每次循环时,x都被另一个值替换,所以之前发生的事情就会消失(除非你用它做了其他的事情)。但是,对于您正在使用的操作,您不会更改列表中任何元素的值。我不好意思混乱。

当你以其他方式这样做时,

for x in range(len(lst)):
    lst[x] += 1

然后你在谈论列表的价值观。 x是变量的索引,因此可以改变该位置列表值的值。

答案 2 :(得分:2)

这里重要的概念是引用的想法。在Python中,变量是对位于内存中的对象的引用。我们使用箭头→表示参考。变量→对象。左边是变量,右边是对象。

可以将数组可视化为引用三个整数对象的三个变量。

a[0] → int(1)
a[1] → int(2)
a[2] → int(3)

现在,整数对象是不可变的。它们无法改变。当您更改整数变量时,您不会更改变量引用的对象。你不能,因为int是不可变的。你可以做的是使变量引用成为一个不同的对象。

直接更新

让我们先看看第二个循环,因为它更简单。如果直接更新阵列会发生什么?

for i in range(0, len(a)):
  a[i] += 1

首先让我们展开循环:

a[0] += 1
a[1] += 1
a[2] += 1

对于整数,a[0] += 1相当于a[0] = a[0] + 1。首先,Python评估a[0] + 1并获得结果int(2)。然后,它会将a[0]更改为引用int(2)。第二和第三个陈述的评估方式相似。

a = [1, 2, 3]  # a[0] → int(1)
               # a[1] → int(2)
               # a[2] → int(3)

a[0] += 1      # a[0] → int(2)
a[1] += 1      # a[1] → int(3)
a[2] += 1      # a[2] → int(4)

间接更新

那么我称之为“间接”更新呢?

for x in a:
  x += 1

展开循环会产生一系列相同的陈述:

x = a[0]
x += 1
x = a[1]
x += 1
x = a[2]
x += 1

每一步都会发生什么,为什么阵列没有改变?

x = a[0]

这使x引用任何对象a[0]引用。 a[0]x都引用相同的int(1)对象,但x未直接与a[0]相关联。它指的是a[0]所指的任何内容,而不是a[0]本身。

x += 1

这会更改x所指的内容。它对a[0]没有影响。

第二次和第三次任务也是如此。结果是x不断更改,而a的元素只是从中读取但从未修改过。因此,当循环终止时a不变。

a = [1, 2, 3]  # a[0] → int(1)
               # a[1] → int(2)
               # a[2] → int(3)

x = a[0]       # x → int(1)
x += 1         # x → int(2)
x = a[1]       # x → int(2)
x += 1         # x → int(3)
x = a[2]       # x → int(3)
x += 1         # x → int(4)

答案 3 :(得分:1)

将其视为第一个循环,x只是替代a中的每个元素。它不是a中的实际元素(尽管id()是因为它们都引用了同一个对象)。当您执行x += 1时,您只是更改了x的值,而不是列表中的值。

在您的第二个for循环中,您通过执行a[i] += 1实际修改了列表。