乘法运算符应用于列表(数据结构)

Ama*_*wal 11 python python-datamodel

我正在阅读如何像计算机科学家一样思考,这是"Python编程"的入门文本.

我想澄清*应用于列表时multiply operator()的行为.

考虑函数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
Run Code Online (Sandbox Code Playgroud)

实际输出是

[[0, 7], [0, 7], [0, 7], [0, 7]]
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

第一版make_matrix失败的原因(如9.8中的书中所述)就是这样

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

我想知道为什么

[[0] * columns] * rows
Run Code Online (Sandbox Code Playgroud)

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

但不是

[[0] * columns]
Run Code Online (Sandbox Code Playgroud)

即为什么[0]连续的每一行都不是其他行元素的别名.

nos*_*klo 18

python中的所有东西都是对象,除非明确要求,否则python永远不会复制.

当你这样做

innerList = [0] * 10
Run Code Online (Sandbox Code Playgroud)

您创建一个包含10个元素的列表,所有这些int0元素都引用同一个对象.

由于整数对象是不可变的,所以当你这样做时

innerList[1] = 15
Run Code Online (Sandbox Code Playgroud)

您正在更改列表的第二个元素,以便它引用另一个整数15.这总是有效的,因为int对象不变性.

这就是为什么

outerList = innerList * 5
Run Code Online (Sandbox Code Playgroud)

将创建一个list具有5个元素的对象,每个元素都是与上面相同innerList的引用.但由于list对象是可变的:

outerList[2].append('something')
Run Code Online (Sandbox Code Playgroud)

是相同的:

innerList.append('something')
Run Code Online (Sandbox Code Playgroud)

因为它们是对同一list对象的两个引用.因此元素最终会出现在那个单元中list.它似乎是重复的,但事实是只有一个list对象,并且很多引用它.

相反,如果你这样做

outerList[1] = outerList[1] + ['something']
Run Code Online (Sandbox Code Playgroud)

在这里,您要创建另一个 list对象(使用+列表是一个显式副本),并将其引用分配到第二个位置outerList.如果你以这种方式"附加"元素(不是真正附加,而是创建另一个列表),innerList将不受影响.