В соответствии с этим, python копирует ссылки при нарезке. Я пробовал следующее:
>>> a=[1,2,3]
>>> b=a[:]
>>> b[1]=0
>>> a
[1, 2, 3]
>>> b
[1, 0, 3]
>>> map(id,a)
[14508376, 14508352, 14508328]
>>> map(id,b)
[14508376, 14508400, 14508328]
Почему b[1]=0
не изменяет a[1]
(что должно быть, если b[1]
действительно является ссылкой на тот же объект, можно подумать)? Вместо этого он создает новую ссылку /id и изменяет новый объект. В любом месте я могу более подробно ознакомиться с этим поведением?
Предположим, вы начинаете с a = [1,2,3]
. В модели данных Python это означает, что a
относится к объекту в памяти:
a -> [ * | * | * ]
| | |
v v v
1 2 3
С b = a
вы просто указываете другое имя на одном и том же объекте:
a -> [ * | * | * ] <- b
| | |
v v v
1 2 3
b[1] = 0
изменяет одну и ту же ссылку a[1] = 0
:
0
^
|
a -> [ * | * | * ] <- b
| |
v v
1 2 3
(2
все еще находится в памяти, возможно, прямо или косвенно ссылаясь на какое-то другое имя, но не через a
или b
).
С помощью b = a[:]
вы создаете новый список, но этот новый список содержит ссылки на один и тот же объект:
a -> [ * | * | * ]
| | |
v v v
1 2 3
^ ^ ^
| | |
b -> [ * | * | * ]
Теперь, когда вы пишете b[1] = 0
, вы не меняете a[1]
, потому что a
и b
являются отдельными объектами списка.
a -> [ * | * | * ]
| | |
v v v
1 2 3
^ ^
| |
b -> [ * | * | * ]
|
v
0
Сообщение блога Ned Batchelder (и последующее обсуждение PyCon) - отличный обзор модели имени Python.
b[1]=0
изменяет ссылку, а не ссылочный объект. Так что теперь два списка имеют разные ссылки. Когда вы видите изменения, отраженные в списках, это происходит не потому, что изменение ссылки вb
меняет ссылку вa
, а потому, что объект, на который ссылаются какa
иb
изменился. Нарисуйте несколько картинок со стрелками, представляющими ссылки, это действительно помогает.