python:循环列表并在循环内赋值

时间:2016-10-09 08:04:49

标签: python

我有以下代码,为什么第一个没有更改alist而第二个更改呢?

alist = [[1,2], [3,4], [5,6]]
for item in alist:
    item = 1
print(alist)

alist = [[1,2], [3,4], [5,6]]
for item in alist:
    item = item.append(10)
print(alist)

7 个答案:

答案 0 :(得分:6)

这是一种有点不直观的变量行为。之所以发生这种情况,是因为在Python中,变量总是引用值。

框和标签

在某些语言中,我们倾向于将变量视为我们放置值的“盒子”;但是,在Python中,它们是引用,并且更像是标记或值的“昵称”。因此,当您将1归因于item时,您只更改变量引用,而不是它所指向的列表。

图形表示可以提供帮助。下图显示了alist = [[1,2], [3,4], [5,6]]

创建的列表

A list with three sublists

鉴于此,让我们看看当我们执行你的第一个循环时会发生什么。

第一个循环

当您执行for item in alist时,您要求解释器从列表中获取每个值,每次一个,将其放在变量item上并在其中执行一些操作。例如,在第一个操作中,我们有了这个新模式:

Now a variable points to a sublist

请注意,我们不会将子列表复制到item;相反,我们通过item 指向。然后,我们执行item = 1 - 但这是什么意思?这意味着我们将item指向值1,而不是指向子列表:

item points to other value now

请注意旧引用丢失(它是红色箭头),现在我们有了新的引用。但我们只是更改了一个指向列表的变量 - 我们没有改变列表本身。

然后,我们进入循环的第二次迭代,现在item指向第二个子列表:

item pointing to the second sublist

当我们再次执行item = 1时,我们只需将变量指向其他值,而不更改列表:

enter image description here

现在,当我们执行第二个循环时会发生什么?

第二个循环

第二个循环作为第一个循环开始:我们让item引用第一个子列表:

Now a variable points to a sublist

然而,第一个区别是我们打电话给item.append()append()方法,因此它可以更改正在调用的对象的值。正如我们所说,我们正在向item指向的对象发送消息以附加值10.在这种情况下,操作是而不是正在在变量item中创建,但直接在它引用的对象中!所以这是调用item.append()

的结果

A list has grown

但是,我们不仅会在列表中附加值!我们还分配了item.append()返回的值。这将切断item对子列表的引用,但这里有一个问题:append()返回None

enter image description here

None

None是一个基本上代表相关值不可用的值。当一个函数返回None时,大部分时间都在说,“我没有任何相关的东西可以让你回来。” append()会直接更改其列表,因此无需返回任何内容。

这很重要,因为您可能认为item会指向附加列表[1, 2, 10],对吧?不,现在它指向None。所以,你会期待下面的代码...

alist = [[1,2], [3,4], [5,6]]
for item in alist:
    item = item.append(10)
    print(item)

要打印这样的内容:

[1, 2, 10]
[3, 4, 10]
[5, 6, 10]

不会发生。 就是这样:

>>> alist = [[1,2], [3,4], [5,6]]
>>> for item in alist:
...     item = item.append(10)
...     print(item)
...
None
None
None

然而,正如我们评论的那样,append()方法改变了列表本身。因此,虽然item变量在赋值后无效,但最终列表已被修改!

>>> print alist
[[1, 2, 10], [3, 4, 10], [5, 6, 10]]

如果要在循环中使用附加列表,只需不要将方法返回值赋给item。这样做:

>>> alist = [[1,2], [3,4], [5,6]]
>>> for item in alist:
...     item.append(10)
...     print item
... 
[1, 2, 10]
[3, 4, 10]
[5, 6, 10]

这是有效的,因为item仍会指向列表。

结论

首先要理解参考文献有点复杂,更不用说掌握了。然而,它们非常强大,如果你按照例子等方法可以学习。你的例子有点复杂,因为这里有更多的事情发生。

Python Tutor可以帮助您了解正在发生的事情,因为它以图形方式执行每个步骤。 Check your own code running there!

答案 1 :(得分:4)

在第一个示例中,item绑定到列表alist中的每个元素,然后item 反弹到整数1。这不会更改列表的元素 - 它只是将名称item重新绑定到int对象1

在第二个示例中,列表元素(本身是列表)由append()变异。 item仍绑定到子列表,因此item.append()会改变子列表。

答案 2 :(得分:2)

您是否忘记list.append()未返回列表本身但实际修改了列表?

item = 1按预期执行。对于for循环的其余部分,item现在是1,而不是它最初的列表。它不会重新分配item是什么,这不是for-loops的作用。

但是,在你的第二个循环中,你现在正在分配item = None,因为append函数不会返回任何内容,只是它会将项目附加到列表中:

>>> L = [1, 2, 3]
>>> L.append(4)
>>> L
[1, 2, 3, 4]

因此,您的代码基本上是说“浏览主列表中的每个子列表并将10附加到其中”。

答案 3 :(得分:2)

=运算符不会对第二个代码进行任何更改,使用.append会导致alist中的更改。使用以下行作为第二个代码中的第三行。您将看到相同的结果:

item.append(10)

在第一个代码item中,item=1指向另一个对象,因此alist不会更改。在第二个代码中,您可以通过调用alist方法对append进行更改。

答案 4 :(得分:2)

它是python中的指针变量。

第一个例子:

for item in alist:
   item = 1

每个项目都指向alist中的每个_item,但突然你改变了项目值,而不是alist中_item的值,因此没有任何改变为alist

第二个例子:

for item in alist:
    item = item.append(10)

每个项目都指向alist中的每个_item,然后将一些内容附加到共享_item的相同内存位置的项目,因为alist中_item的结果值也会更改,alist也会更改。

答案 5 :(得分:1)

引用the document

  

for循环对目标列表中的变量进行赋值。   这会覆盖以前对这些变量的所有分配,包括   在for-loop套件中制作的那些:

for i in range(10):
    print(i)
    i = 5             # this will not affect the for-loop
                      # because i will be overwritten with the next
                      # index in the range

所以你的第二个例子与:

相同
alist = [[1,2], [3,4], [5,6]]
for item in alist:
    item.append(10)    # this statement modifies each item in alist
                       # , which is what item the variable "points to"
print(alist)

也就是说,item是每次迭代中的新变量 。因此,在任何特定迭代中为其赋值都是没有意义的,因为它的值将被下一次迭代开始时alist中对下一项的引用所覆盖。

答案 6 :(得分:0)

写作时

for item in alist:

您实际上是在liast变量的item中创建了每个项目的副本,而您获取对item的引用。

但是,append就地更改了列表并且没有返回值,这就是为什么您将值更改为None(到期)的原因分配 - 如果你删除它,你将使附加工作正常)。