Если срез Python скопирует ссылку, почему я не могу использовать ее для изменения исходного списка? - PullRequest
1 голос
/ 03 мая 2020

Я знаю, что Списки нарезки не генерируют копии объектов в списке; он просто копирует ссылки на них.

Но если это так, то почему это не работает?

l = [1, 2, 3]

# Attempting to modify the element at index 1
l[0:2][-1] = 10

# but the attempt fails. The original list is unchanged
l
> [1, 2, 3]

Не должно l[0:2][-1] указывать на элемент по индексу 1 исходного списка?

Ответы [ 3 ]

2 голосов
/ 03 мая 2020

Нарезка list возвращает новый мелко скопированный list объект. Хотя вы правы в том, что он не выполняет глубокое копирование элементов оригинального списка, в результате получается совершенно новый list, отличный от оригинала.

См. Учебник Python 3 :

Все операции срезов возвращают новый список, содержащий запрошенные элементы. Это означает, что следующий фрагмент возвращает поверхностную копию списка:

>>> squares = [1, 4, 9, 16, 25]
>>> squares[:]
[1, 4, 9, 16, 25]

Рассмотрим

>>> squares[:] is squares
False
1 голос
/ 05 мая 2020

Вы правы, что нарезка не копирует элементы в списке. Тем не менее, он создает новый объект списка.

Ваш комментарий предполагает недопонимание:

# Attempting to modify the element at index 1
l[0:2][-1] = 10

Это не модификация элемента , это модификация список . Другими словами, это действительно «изменить список так, чтобы индекс 1 теперь указывал на число 10». Поскольку ваш срез создал новый список, вы просто изменяете этот новый список, чтобы он указывал на какой-то другой объект.

В своем комментарии к ответу oldrinb вы сказали:

Почему l[0:1] и l[0:1][0] разные? Разве они не должны ссылаться на один и тот же объект, то есть на первый элемент l?

Помимо того, что l[0:1] является списком, в то время как l[0:1][0] является отдельным элементом, здесь опять то же недоразумение. Предположим, что some_list является списком, а объект с индексом ix равен obj. Это:

some_list[ix] = blah

. , , это операция на some_list. Объект obj не задействован. Это может сбивать с толку, потому что это означает, что some_list[ix] имеет слегка различную семантику в зависимости от того, на какой стороне присвоения он находится. Если вы делаете

blah = some_list[ix] + 2

. , .то вы действительно оперируете объектом внутри списка (т. е. он совпадает с obj + 2). Но когда операция индексирования находится слева от назначения, она больше не включает в себя содержащийся объект, а только сам список.

Когда вы присваиваете индекс списка, вы модифицируете список , а не объект внутри него. Так что в вашем примере l[0] совпадает с l[0:2][0], но это не имеет значения; поскольку ваша индексация является целью назначения, она изменяет список и не заботится о том, какой объект там уже находился.

1 голос
/ 03 мая 2020

Чтобы объяснить это лучше, предположим, что вы написали

l = [1, 2, 3]
k = l[0:2]
k[-1] = 10

Я надеюсь, вы согласитесь, что это эквивалентно.

Теперь давайте разберем отдельные утверждения:

l = [1, 2, 3]

При этом создаются следующие объекты и ссылки:

id  object
--  --------
0   <int 1>
1   <int 2>
2   <int 3>
3   <list A>
name  →  id
----     --
l     →  3
l[0]  →  0
l[1]  →  1
l[2]  →  2

k = l[0:2]

Создается новый список <list B> содержащий копии ссылок, содержащихся в l:

id  object
--  --------
0   <int 1>
1   <int 2>
2   <int 3>
3   <list A>
<b>4   <list B></b>
name  →  id
----     --
l     →  3
l[0]  →  0
l[1]  →  1
l[2]  →  2
<b>k     →  4</b>
<b>k[0]  →  0</b>  (copy of l[0])
<b>k[1]  →  1</b>  (copy of l[1])

k[-1] = 10

Сначала индекс -1 преобразуется в индекс 1 (поскольку k имеет длину 2) , так что это эквивалентно k[1] = 10. Это назначение означает, что объекты и ссылки обновляются следующим образом:

id  object
--  --------
0   <int 1>
1   <int 2>
2   <int 3>
3   <list A>
4   <list B>
<b>5   <int 10></b>
name  →  id
----     --
l     →  3
l[0]  →  0
l[1]  →  1
l[2]  →  2
k     →  4
k[0]  →  0
<b>k[1]  →  5</b>

Обратите внимание, как это не влияет на l и l[0] до l[2]. QED.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...