#python
#python
Вопрос:
Я пытаюсь понять разницу между циклическим перебором списка и циклическим перебором «фрагментарной» копии списка.
Так, например, в следующем списке элемент, длина которого больше 6, добавляется в начало списка:
words = ['cat', 'window', 'blahblah']
for word in words[:]:
if len(word) > 6:
words.insert(0, word)
print(words)
words = ['blahblah', 'cat', 'window', 'blahblah']
Затем я запускаю следующее, чтобы понять, почему это неправильный способ сделать это, но мой интерпретатор зависает, и я должен выйти. Почему это происходит? Я просто добавляю что-то в начало моего списка, что разрешено, поскольку списки изменчивы…
for word in words:
if len(word) > 6:
words.insert(0, word)
Может кто-нибудь, пожалуйста, помочь мне понять, почему этот последний бит останавливает мою программу?
Комментарии:
1. Это потому, что вы изменяете и добавляете список по мере его прохождения. Не рекомендуется изменять то, что вы просматриваете.
Ответ №1:
Список words
состоит из трех элементов. Копия words
также выполняет. Вы выполняете итерацию по копии, вставляете что-то, words
если текущий элемент длиннее 6 символов, и готово.
Теперь давайте посмотрим, что происходит, когда вы выполняете итерацию words
напрямую:
Первые два шага итерации выполняются нормально, потому что условие равно False . Но поскольку len('blahblah') > 6
теперь вы вставляете 'blahblah'
в начало списка. Теперь список выглядит следующим образом:
['blahblah', 'cat', 'window', 'blahblah']
Вы только что видели третий элемент, так что теперь цикл продолжается и просматривается четвертый элемент, но поскольку вы вставили что-то в начало списка, остальная часть списка сдвинулась, и снова появился новый четвертый элемент 'blahblah'
. blahblah
по-прежнему длиннее 6 символов, вы вставляете его снова в начале и застреваете в бесконечном цикле:
['cat', 'window', 'blahblah']
^
['cat', 'window', 'blahblah']
^
['cat', 'window', 'blahblah']
^
['blahblah', 'cat', 'window', 'blahblah']
^
['blahblah', 'blahblah', 'cat', 'window', 'blahblah']
^
...
Комментарии:
1. Когда я пишу
print words[:]
в цикле, я вижу, что он растет — это верно и дляprint words
also. Не понимаю, почему он не переходит в бесконечный цикл для 1-го случая.2. Если вы пишете
print words[:]
в цикле, он каждый раз создает новую копию, но копия, которую вы повторяете, не меняется. Вы можете увидеть это, написавcopy = words[:]
перед циклом, выполнив итерациюcopy
и распечатавcopy
внутри цикла.
Ответ №2:
В вашем первом подходе вы выполняете мелкую копию своего списка words
, перебираете его и добавляете в список длинные слова words
. Таким образом, вы выполняете итерацию по фиксированному списку и расширяете другой список.
При вашем последнем подходе список words
растет с каждой итерацией, поэтому вы находитесь в бесконечном цикле, когда вы перебираете его, и он продолжает расти.
Ответ №3:
Когда вы выполняете words[:]
, вы выполняете итерацию по копии list , тогда как с words
помощью, вы выполняете итерацию по исходной копии list .
В этом случае II
ваш интерпретатор зависает, потому что, когда вы находитесь на последнем индексе, условие выполняется, и вы вставляете элемент в начало списка. Теперь есть еще один индекс, который должен быть повторен циклом. Опять же, условие удовлетворяет, и оно продолжает работать таким образом, что приводит к бесконечному циклу.
Где, поскольку это не так words[:]
, поскольку список, в который вы добавляете, и тот, в котором вы выполняете итерацию, отличаются.
Ответ №4:
Следующий цикл
for word in words:
// do something
примерно эквивалентно следующему (когда words
это список, а не другой вид iterable
):
i = 0
while i != len(words):
word = words[i]
// do something (assuming no 'continue' here)
i = 1
Поэтому, когда во время цикла вы вставляете что-то в свой список перед текущей позицией, то во время следующей итерации вы в конечном итоге обрабатываете тот же элемент, что и для предыдущей итерации. В вашем случае это приводит к бесконечному циклу.
Ответ №5:
words[:]
означает, что новая копия words
и длина фиксирована. Итак, вы выполняете итерацию по фиксированному списку.
Но во второй ситуации повторение и расширение того же списка, что делает его бесконечным.
words = ['cat', 'window', 'blahblah']
new_words = [_ for _ in words if len(_) > 6]
print(new_words)
Комментарии:
1. Неправильный ответ, потому что пользователь не спрашивает, как он должен это делать, а почему метод, которому он следует, терпит неудачу.
Ответ №6:
В случае, если вы хотите увидеть, что именно происходит на фоне вставки в список (слова) против копии фрагмента (слова[:]), вы можете изменить / табулировать печать, чтобы увидеть бесконечный цикл, поскольку бесконечный цикл не может быть виден в его исходном местоположении в скрипте:
for w in words:
if len(w) > 6:
words.insert(0, w)
print(words) #prints after each insert, let you see the infinite loop