我在读如何看待一个计算机科学家这是“Python编程”的介绍文字

要说明当施加到列表乘法操作符(*)的行为。

考虑函数的 make_matrix

def make_matrix(rows, columns):
"""
  >>> make_matrix(4, 2)
  [[0, 0], [0, 0], [0, 0], [0, 0]]
  >>> m = make_matrix(4, 2)
  >>> m[1][1] = 7
  >>> m
  [[0, 0], [0, 7], [0, 0], [0, 0]]
"""
return [[0] * columns] * rows

实际的输出是

[[0, 7], [0, 7], [0, 7], [0, 7]]

正确的版本的的 make_matrix 是:

def make_matrix(rows, columns):
"""
  >>> make_matrix(3, 5)
  [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
  >>> make_matrix(4, 2)
  [[0, 0], [0, 0], [0, 0], [0, 0]]
  >>> m = make_matrix(4, 2)
  >>> m[1][1] = 7
  >>> m
  [[0, 0], [0, 7], [0, 0], [0, 0]]
"""
matrix = []
for row in range(rows):
    matrix += [[0] * columns]
return matrix

之所以的第一版本的 make_matrix 失败(如在9.8书中解释)是

...每行是其他行的别名...

不知为何

[[0] * columns] * rows

原因 ...每行是其他行的别名...

但不

[[0] * columns]

即。为什么一行中的每个[0]不是其他行元件的一个别名。

有帮助吗?

解决方案

在Python一切都是对象,和Python从不拷贝,除非明确地要求这样做。

当您

innerList = [0] * 10

创建具有10个元素,的列表所有这些指的同一int对象的 0

由于整数对象的不可变下,当你

innerList[1] = 15

,以便它是指另一个整数 15 你正在改变列表的第二元件。永远奏效,因为 int 的物体永恒性。

这就是为什么

outerList = innerList * 5

将创建具有5个元素一个list对象,每一个是与参考的相同innerList 正如上面。但是,由于list对象的可变

outerList[2].append('something')

是相同的:

innerList.append('something')

由于它们是两个引用的相同list对象即可。因此,该元素在单一list结束。这似乎被复制,但事实是,仅存在一个对象list,以及它的许多参考。

相反,如果你做

outerList[1] = outerList[1] + ['something']

下面您的创建另一个 list对象(使用+处理列表是显式的副本),并分配对它的引用进入outerList的第二位置。如果这种方式(不是真的追加,但创建另一个列表)“追加”的元素,innerList将不会受到影响。

其他提示

列表不是基元,它们通过引用传递。列表的副本是一个指针到一个列表(在C行话)。除非你做一个浅拷贝,你做的名单有什么事情发生到列表中的所有副本,并对其内容的副本。

[[0] * columns] * rows

哎呀,我们刚刚作出指针的大名单[0]。改变之一,你改变他们。

整数不通过引用传递,它们确实复制,因此[0] *内容实拍许多新的0和其附加到列表中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top