Оператор Multiply, применяемый к списку (структура данных)
Я читаю как думать, как компьютерщик который является вводным текстом для "программирования 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]
в строке не является псевдонимом другого элемента строки.
2 ответов
все в python являются объектами, и python никогда не делает копий, если explicity не попросит об этом.
когда вы
innerList = [0] * 10
создать список из 10 элементов, все они ссылаются на одно и то же int
объект 0
.
так как число объектов неизменяемые, когда вы делаете
innerList[1] = 15
вы меняете второй элемент списка, чтобы он ссылался на другой целое число 15
. Это всегда работает из-за int
иммутабельность объектов.
вот почему
outerList = innerList * 5
создать list
объект с 5 элементами, каждый из которых является ссылкой на тот же innerList
как и выше. Но с list
объекты mutable:
outerList[2].append('something')
- это то же, что:
innerList.append('something')
потому что это две ссылки на то же самое list
объект. Таким образом, элемент заканчивается в этом одном list
. Похоже, что он дублируется, но факт в том, что есть только один list
объект и множество ссылок на него.
по контрасту, если вы делаете
outerList[1] = outerList[1] + ['something']
вы создания другое list
объект (через +
со списками является явной копией), и присвоение ссылки на нее во вторую позицию outerList
. Если вы" добавляете " элемент таким образом (не действительно добавляя, но создавая другой список),innerList
будет в силе.списки не являются примитивами, они передаются по ссылке. Копия списка-это указатель на список (на жаргоне C). Все, что вы делаете со списком, происходит со всеми копиями списка и копиями его содержимого, если вы не делаете мелкую копию.
[[0] * columns] * rows
Oops, мы только что сделали большой список указателей на [0]. Измените одного, и вы измените их всех.
целые числа не передаются по ссылке, они действительно копируются ,поэтому [0] * содержимое действительно делает много новых 0 и добавляю их в список.