代码之家  ›  专栏  ›  技术社区  ›  Aman Aggarwal Charlie

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

  •  11
  • Aman Aggarwal Charlie  · 技术社区  · 15 年前

    我在读书 How to think like a computer scientist 这是“Python编程”的介绍性文本。

    我想澄清乘法运算符的行为( * )当应用于列表时。

    考虑函数 加梅矩阵

    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]]
    

    正确的版本 加梅矩阵 是:

    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
    

    第一版的原因 加梅矩阵 失败(如本书9.8节所述)是

    …每行都是其他行的别名…

    我想知道为什么

    [[0] * columns] * rows
    

    原因 …每行都是其他行的别名…

    但不是

    [[0] * columns]
    

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

    2 回复  |  直到 15 年前
        1
  •  18
  •   nosklo    15 年前

    python中的一切都是对象,除非明确要求,否则python从不复制。

    当你这样做的时候

    innerList = [0] * 10
    

    创建一个包含10个元素的列表, 他们都指同一个 int 对象 0 .

    因为整数对象是 不变的 当你这样做的时候

    innerList[1] = 15
    

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

    这就是为什么

    outerList = innerList * 5
    

    将创建一个 list 对象有5个元素,每个元素都是对 相同的 innerList 正如上面一样。但自从 列表 对象是 易变的 :

    outerList[2].append('something')
    

    相同:

    innerList.append('something')
    

    因为它们是对 相同的 列表 对象 . 所以这个元素最后会出现在 列表 . 它似乎是复制的,但事实上只有一个 列表 对象,以及对它的许多引用。

    相反,如果你这样做的话

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

    给你 创建 另一个 列表 对象 (使用) + 使用列表是一个显式副本),并将对它的引用分配到 outerList . 如果您以这种方式“附加”元素(不是真正附加,而是创建另一个列表), 内列表 不会受到影响。

        2
  •  -3
  •   SpliFF    15 年前

    列表不是基元,它们是通过引用传递的。列表的副本是指向列表的指针(用C术语)。对列表所做的任何操作都会发生在列表的所有副本及其内容的副本上,除非您只进行简单的复制。

    [[0] * columns] * rows
    

    哎呀,我们刚刚列出了一大串指向[0]的指针。改变一个,你就改变了所有。

    整数不是通过引用传递的,它们确实是被复制的,因此[0]*内容实际上是生成许多新的0并将它们附加到列表中。