Как назначение работает со срезом списка Python?
Python doc говорит, что нарезка списка возвращает новый список.
Теперь, если возвращается "новый" список, у меня есть следующие сомнения, связанные с "Назначением на кусочки"
a = [1, 2, 3]
a[0:2] = [4, 5]
print a
Теперь результат будет:
[4, 5, 3]
- Как что-то, что возвращает что-то, может появиться на левой стороне выражения?
- Да, я прочитал документы, и там написано, что это возможно. Теперь, когда нарезка списка возвращает "новый" список, почему изменяется первоначальный список? Я не могу понять механику, стоящую за этим.
Ответы
Ответ 1
Вы смешиваете две разные операции, которые используют очень похожий синтаксис:
1) нарезка:
b = a[0:2]
Это делает копию среза a
и назначает его b
.
2) назначение среза:
a[0:2] = b
Это заменяет срез a
содержимым b
.
Хотя синтаксис подобен (я полагаю, по дизайну!), это две разные операции.
Ответ 2
При указании на левой стороне a
=
оператора, вы используете Python нормальное назначение, которое изменяет имя a
, в данном контексте, чтобы указать новое значение. Это не меняет предыдущее значение, на которое указывал a
.
Указывая a[0:2]
в левой части оператора =
, вы сообщаете Python, что хотите использовать Slice Assignment. Назначение фрагментов - это специальный синтаксис для списков, в который можно вставлять, удалять или заменять содержимое из списка:
Вставка:
>>> a = [1, 2, 3]
>>> a[0:0] = [-3, -2, -1, 0]
>>> a
[-3, -2, -1, 0, 1, 2, 3]
Удаление:
>>> a
[-3, -2, -1, 0, 1, 2, 3]
>>> a[2:4] = []
>>> a
[-3, -2, 1, 2, 3]
Замена:
>>> a
[-3, -2, 1, 2, 3]
>>> a[:] = [1, 2, 3]
>>> a
[1, 2, 3]
Замечания:
Длина среза может отличаться от длины назначенной последовательности, тем самым изменяя длину целевой последовательности, если целевая последовательность это позволяет. - источник
Назначение фрагментов обеспечивает функцию, аналогичную распаковке кортежей. Например, a[0:1] = [4, 5]
эквивалентно:
# Tuple Unpacking
a[0], a[1] = [4, 5]
С помощью Tuple Unpacking вы можете изменять непоследовательные списки:
>>> a
[4, 5, 3]
>>> a[-1], a[0] = [7, 3]
>>> a
[3, 5, 7]
Однако распаковка кортежа ограничена заменой, поскольку вы не можете вставлять или удалять элементы.
До и после всех этих операций, a
и тот же точный список. Python просто предоставляет хороший синтаксический сахар для изменения списка на месте.
Ответ 3
Я сталкивался с тем же вопросом раньше, и он касался языковой спецификации. Согласно заявлениям- уступкам,
-
Если левой стороной назначения является подписка, Python вызовет __setitem__
для этого объекта. a[i] = x
эквивалентно a.__setitem__(i, x)
.
-
Если левой стороной присваивания является слайс, Python также вызовет __setitem__
, но с другими аргументами: a[1:4]=[1,2,3]
эквивалентно a.__setitem__(slice(1,4,None), [1,2,3])
Поэтому срез списка в левой части '=' ведет себя по-разному.
Ответ 4
Нарезая левую часть операции присваивания, вы указываете, какие элементы назначать.