Удаление Объекта Из Списка - во время повторения - что случилось с этой идиомой?

Как эксперимент, я сделал это:

letters=['a','b','c','d','e','f','g','h','i','j','k','l']
for i in letters:
    letters.remove(i)
print letters

Последняя печать показывает, что не все объекты были удалены? (любой был).

IDLE 2.6.2      
>>> ================================ RESTART ================================
>>> 
['b', 'd', 'f', 'h', 'j', 'l']
>>> 

Каково объяснение этого? Как это могло это быть переписанным для удаления каждого объекта?

24
задан SilentGhost 24 May 2010 в 12:03
поделиться

6 ответов

Некоторые ответы объясняют, почему это происходит, а некоторые объясняют, что вы должны были сделать. Я беззастенчиво складываю кусочки воедино.


В чем причина этого?

Потому что язык Python предназначен для обработки этого варианта использования по-другому. В документации поясняется:

Небезопасно изменять последовательность, по которой выполняется итерация в цикле (это может происходить только для изменяемых типов последовательностей, таких как списки). Если вам нужно изменить список, который вы перебираете (например, чтобы дублировать выбранные элементы), вы должны перебирать копию .

Акцент мой. См. Дополнительную информацию на связанной странице - документация защищена авторским правом, и все права защищены.

Вы можете легко понять, почему вы получили то, что получили, но в основном это неопределенное поведение , которое можно легко изменить без предупреждения от сборки к сборке. Просто не делай этого.

Это как удивляться, почему i + = i ++ + ++ i делает то, черт возьми, это строка делает с вашей архитектурой в конкретной сборке вашего компилятора для вашего языка - включая, помимо прочего, уничтожение вашего компьютера и , заставляющее демонов вылетать из вашего носа :)


Как это можно переписать, чтобы удалить все элементы?

  • del письма [:] (если нужно изменить все ссылки на этот объект)
  • букв [:] = [] (если нужно изменить все ссылки на этот объект)
  • букв = [] (если вы просто хотите работать с новым объектом)

Может быть, вы просто хотите удалить некоторые элементы в зависимости от условия? В этом случае вам следует перебрать копию списка.Самый простой способ сделать копию - создать фрагмент, содержащий весь список, с синтаксисом [:] , например:

#remove unsafe commands
commands = ["ls", "cd", "rm -rf /"]
for cmd in commands[:]:
  if "rm " in cmd:
    commands.remove(cmd)

Если ваша проверка не особенно сложна, вы можете (и, вероятно, должны) вместо фильтра:

commands = [cmd for cmd in commands if not is_malicious(cmd)]
38
ответ дан 28 November 2019 в 22:36
поделиться

то, что вы хотите сделать, это:

letters[:] = []

или

del letters[:]

Это сохранит исходный объект букв, на которые указывал . Другие параметры, такие как letter = [] , создадут новый объект и укажут на него letter : старый объект обычно через некоторое время будет собираться сборщиком мусора.

Причина, по которой не все значения были удалены, заключается в том, что вы меняете список во время итерации по нему.

ETA : если вы хотите отфильтровать значения из списка, вы можете использовать такие интерпретации списка:

>>> letters=['a','b','c','d','e','f','g','h','i','j','k','l']
>>> [l for l in letters if ord(l) % 2]
['a', 'c', 'e', 'g', 'i', 'k']
5
ответ дан 28 November 2019 в 22:36
поделиться

Вероятно, python использует указатели, и удаление начинается спереди. Переменная «письма» во второй строке частично имеет другое значение, чем переменная «буквы» в третьей строке. Когда i равно 1, тогда a удаляется, когда i равно 2, тогда b был перемещен в позицию 1, а c удаляется. Вы можете попробовать использовать «пока».

1
ответ дан 28 November 2019 в 22:36
поделиться

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

for i in letters[:]:
  letters.remove(i)
7
ответ дан 28 November 2019 в 22:36
поделиться

Он удаляет первое вхождение, а затем проверяет наличие следующего числа в последовательности. Поскольку последовательность изменилась, она принимает следующее нечетное число и так далее ...

  • возьмите «a»
  • удалите «a» -> первый элемент теперь «b»
  • возьмите следующий элемент, » c " -...
5
ответ дан 28 November 2019 в 22:36
поделиться

Вы не можете перебирать список и изменять его одновременно, вместо этого перебирать срез:

letters=['a','b','c','d','e','f','g','h','i','j','k','l']
for i in letters[:]: # note the [:] creates a slice
     letters.remove(i)
print letters

Тем не менее, для такой простой операции, как эта, вы должны просто использовать:

letters = []
9
ответ дан 28 November 2019 в 22:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: