у меня вопрос. Я боюсь, что это может быть очевидно для вас, но я не совсем понимаю это в данный момент.
Я только что прочитал о назначении slice и о том, как назначение пустого списка работает как элемент delete, fe:
>> L=['a','b','c','d']
>> L[2:3] = []
>> L
['a', 'b', 'd']
Но вот мой вопрос - не логичнее ли ожидать этого вывода?
['a', 'b', [], 'd']
Я знаю, что вывод выше будет правдой, если мой код будет выглядеть так:
>> L=['a','b','c','d']
>> L[2:3] = [[]]
>> L
но почему он построил этот путь, а не как fe:
>> L=['a','b','c','d']
>> L[2:3] = None
>> L
Это выглядит слишком сложным для меня, потому что я ожидаю, что когда я сделаю slice-присваивание, я не ожидаю, что в этой ситуации он изменит длину моего списка, или, может быть, я хочу просто удалить срез и инициировать пустой список на в то же время.
EDIT: Я не знаю, был ли я достаточно ясным - я не понимал, почему - при выполнении назначения slice - интерпретатор python удаляет элемент в списке вместо изменения этого элемента для пустого списка.
Я думаю, что путаница исходит из того факта, что вы действительно нарезаете и не индексируете. Заметим:
>>> L = ['a','b','c','d']
>>> L[2] = []
>>> L
['a', 'b', [], 'd']
Заметим, что L[2:3]
"идентичен" L[2]
в отношении диапазона 2-3, всего 2 (поскольку нарезка не включена). Однако нарезка и индексирование - это два разных поведения, поскольку нарезка может изменить длину списка, тогда как индексирование просто изменяет существующий элемент.
Причина, по которой пустой список работает таким образом, связана с тем, как работает назначение среза. Когда вы назначаете срез, python распаковывает то, что вы ему даете, и сохраняет свои результаты в индексах. Заметим:
>>> L = ['a', 'b', 'c', 'd']
>>> L[2:4] = 'e'
>>> L
['a', 'b', 'e']
>>> L = ['a', 'b', 'c', 'd']
>>> L[2:4] = 'efgh'
>>> L
['a', 'b', 'e', 'f', 'g', 'h']
Поведение L[2:4] = 'e'
и L[2:4] = ['e']
одно и то же в python из-за поведения строк в Python: они могут быть перезаписаны и, следовательно, распакованы.
Поэтому, когда вы помещаете L[2:4] = []
, он распаковывает все элементы []
и присваивает их содержимое индексам 2 и 3. Конечно, поскольку нет элементов, он не присваивает их ничто (примечание: отличается от None
или ""
- буквально ничто) и, следовательно, удаляется.
Когда вы назначаете фрагмент списка, аргумент правой руки должен быть итерируемым объектом. Этот итеративный файл распаковывается, а значения заменяют значения в нарезанной части исходной последовательности. Для срезов с размером шага один (или отрицательный) это работает независимо от того, имеют ли срез и итерабельность одинаковый размер.
Рассмотрим следующие примеры:
a = [1, 2, 3, 4]
a[1:3] = [5, 6, 7]
print(a) # prints [1, 5, 6, 7, 4]
a = [1, 2, 3, 4]
a[1:3] = [5]
print(a) # prints [1, 5, 4]
Конкретная ситуация, о которой вы просите, является лишь краевым случаем такого поведения. Когда вы назначаете пустой список срезу, нарезанные значения удаляются, и ничто не заменяет их. Любой пустой итеративный объект будет работать одинаково.
Однако это не стандартный способ удаления элементов. Обычный способ - использовать инструкцию del
. Назначение среза, такое a[1:3] = []
в точности эквивалентно del a[1:3]
, но последнее предпочтительнее, поскольку оно гораздо более четко указывает на то, что ожидается.
Нарезка не меняет длину, присваивание делает. Экстракты нарезки. Индексирование выбирает один элемент. Индексирование не изменяет длину, присваивание делает.
>>> L = ['a','b','c','d']
>>> L[2:4]
['c', 'd'] # that the extraction of a slice.
>>> L[2:4] = [] # that assignment using a slice and an empty list as operands.
>>> L
['a', 'b']
>>>L[1]
'b' # that the selection of an index
>>>L[1] = 0
>>>L
['a', 0] #that assignment using an index and integer as operands.
Таким образом, извлечение из списка строк должно по-прежнему оставлять вас со списком строк, а не строк и пустых списков - это будет изменение типа.