Присвоение значения элементу среза в Python

Это простой вопрос о том, как Python обрабатывает данные и переменные. Я много экспериментировал и в основном выяснил Python, за исключением того, что это продолжает меня запутывать:

[edit: я разделил и переставил примеры для ясности]

Пример 1:

>>> a = [[1], 2]
>>> a[0:1]
[[1]]
>>> a[0:1] = [[5]]
>>> a
[[5], 2] # The assignment worked.

Пример 2:

>>> a = [[1], 2]
>>> a[0:1][0]
[1]
>>> a[0:1][0] = [5]
>>> a
[[1], 2] # No change?

Пример 3:

>>> a = [[1], 2]
>>> a[0:1][0][0]
1
>>> a[0:1][0][0] = 5
>>> a
[[5], 2] # Why now?

может кто-нибудь объяснить мне, что происходит здесь?

до сих пор ответы, кажется, утверждают, что a[0:1] возвращает новый список, содержащий ссылку на первый элемент a. Но я не понимаю, как это объясняет Пример 1.

3 ответов


есть[0:1] возвращает новый массив, который содержит ссылку на массив [1], таким образом, вы в конечном итоге изменяя внутренний массив через справочную звонить.

Почему в первом случае не изменяется [1] массив, который вы присваиваете скопированный внешний массив новый внутренний массив.

нижняя строка-a[0: 1] возвращает копию данных, но внутренние данные не копируются.


мое понимание нарезки возвращает новый объект. То есть возвращаемое значение-это новый список.

следовательно, вы не можете использовать оператор присваивания для изменения значений исходного списка

>>> a = [[1], 2, 3]
>>> k = a[0:2]
>>> id(a)
4299352904
>>> id(k)
4299353552
>>> 

>>> id(a)
4299352904
>>> id(a[0:2])
4299352832

еще несколько игр по линиям

>>> k = 5
>>> 
>>> id(k)
4298182344
>>> a[0] = [1,2]
>>> a
[[1, 2], 2, 3]
>>> id(a)
4299352904
>>> 

[Edit: на второй части вопроса]

>>> a[0:1] = [[5]]

следующие обозначения также обычно называются назначение ломтик Поведение для встроенных списков является атомарным (delete + insert) все происходит за один раз. Я понимаю, что это не разрешено для пользовательской последовательности.


существует три различных операции с индексами, все они переведены на вызовы методов:

  • a[i] = b =>a.__setitem__(i, b)
  • del a[i] =>a.__delitem__(i)
  • a[i] используется как выражение =>a.__getitem__(i)

здесь a, b и i - это выражения, и i может содержать объектов-фрагментов создано с использованием синтаксиса двоеточия. Например:

>>> class C(object):
...     def __setitem__(self, *a):
...             print a
... 
>>> C()[1] = 0
(1, 0)
>>> C()['foo'] = 0
('foo', 0)
>>> C()['foo':'bar'] = 0
(slice('foo', 'bar', None), 0)
>>> C()['foo':'bar',5] = 0
((slice('foo', 'bar', None), 5), 0)

Итак, что происходит в третий пример:

a[0:1][0][0] = 5

становится

a.__getitem__(slice(0,1)).__getitem__(0).__setitem__(0, 5)

первый __getitem__ возвращает копию части списка, а второй __getitem__ возвращает фактический список внутри этого, который затем изменяется с помощью __setitem__.

ваш второй пример с другой стороны становится

a.__getitem__(slice(0,1)).__setitem__(0, 5)

так __setitem__ вызывается на нарезанной копии, оставляя исходный список нетронутым.