Странное поведение, наблюдаемое при переборе списка в python

#python #python-3.x #python-2.7

#python #python-3.x #python-2.7

Вопрос:

У меня есть небольшой вопрос, позвольте мне поделиться небольшим фрагментом кода

 num = [1, 2, 3, 4]

for i in num:
    print(i)
    num[2] = 5
  

здесь вывод

 1
2
5
4
  

значение итератора было обновлено до 5 вместо 3 на 3-й итерации, теперь, если я сделаю это

 num = [1, 2, 3, 4]

for i in num:
    print(i)
    num = [5 if j == 3 else j for j in num]
  

вывод

 1
2
3
4
  

итератор остался прежним на 3-й итерации
Кто-нибудь знает причину такого поведения?
(Я наблюдал это в Python 3.8 или 2.7)

Комментарии:

1. Общая идея состоит в том, чтобы не обновлять коллекцию, которую вы перебираете в цикле. кстати, в ваших примерах кода нет итераторов.

2. for Цикл получает итератор один раз num в начале цикла, который затем просматривает каждое значение в списке одно за другим. num = ... заменяет переменную num другим списком, но это не представляет интереса для for цикла, потому что он не просматривается num снова после того, как он уже получил свой итератор.

3. Ваш первый пример изменяет список; ваш второй пример создает новый список и присваивает его num , пока вы продолжаете перебирать исходный список.

Ответ №1:

Когда вы запускаете цикл for, он принимает идентификатор предоставленного объекта и выполняет итерацию по нему.

В первом фрагменте кода вы изменяете элемент исходного объекта, поэтому, когда итератор достигает второго элемента, он принимает обновленное значение.

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

Способ проверить это поведение — получить идентификатор переменной до и после изменений и посмотреть, как он не меняется в первом случае, но меняется во втором случае:

 my_list = [1, 2, 3]
original_id = id(my_list)

# Check if the object identification changes after modifying one element
my_list[2] = 4
new_id = id(my_list)
if original_id == new_id:
   print("1st case: The ID stays the same")
else:
   print("1st case: The ID has changed")

# Check now what happens if you create a new list
my_list = [3, 2, 1]
new_id = id(my_list)
if original_id == new_id:
   print("2nd case: The ID stays the same")
else:
   print("2nd case: The ID has changed")
  

Полученный результат следующий:

 1st case: The ID stays the same
2nd case: The ID has changed
  

Комментарии:

1. Рад, что это помогло. Если вам интересно узнать больше об этой теме, выполните поиск по изменяемым и неизменяемым объектам в Python 😉

Ответ №2:

В вашем первом коде вы num[2]=5 заменяете значения в самом экземпляре первого цикла, поэтому 5 печатается в обычном цикле.

Ваш второй код:

На самом деле он заменяет и i печатается только во втором коде.

Вам нужно распечатать num , чтобы проверить замененное значение.

Код:

 num = [1, 2, 3, 4]

for i in num:
    print(i)
    num = [5 if j==3 else j for j in num ]
    
print (num)# This line
  

Вывод:

 1
2
3
4
[1, 2, 5, 4]

  

Комментарии:

1. Да, но я хотел знать, почему «i» не обновлялся как предыдущий.

2. Также объясняется в ответе. На самом деле он мутировал в первом экземпляре самого lopp. Итак, 5 печатается в экземпляре 3-го цикла.

Ответ №3:

for Цикл уже получает итератор num , и в то время как внутри цикла вы изменяете num , for цикл больше не просматривается num и повторяется с использованием старого списка.