题
我在读如何看待一个计算机科学家这是“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和其附加到列表中。