Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 16, 2013 11:18:47

soln
От:
Зарегистрирован: 2011-11-02
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

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

Вобщем столкнулся я с непонятным для меня поведением for, а имено. Если преберать for(м) последовательность и при каждой итерации удалять из этого объекта возвращаемое значение.
То ощущение что фор бежит через 1
Я понимаю что, влюбом случае такие вещи нужно делать с копией объекта,
но всеже почему он так себя ведет?

In [87]: a = [1,2,3,4,5]
In [88]: [a.pop(a.index(x)) for x in a]
Out[88]: [1, 3, 5]
In [89]: a
Out[89]: [2, 4]
In [90]: a = [1,2,3,4,5]
In [91]: for x in a: print a.pop(a.index(x))
1
3
5
In [92]: a
Out[92]: [2, 4]



Офлайн

#2 Ноя. 16, 2013 12:36:39

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

Я Бизли не читал, попробую объяснить на пальцах.
Как Вы думаете, как внутри питона происходит перебор списка?
Я тоже не знаю как, но давайте предположим, что по индексу.
То есть вместо

for i in lst:
где-то там внутри делается такое
for (int i; i<len(lst); i++)
{
lst[i]
}
Ну то есть классический цикл. Что же происходит, если мы в процессе перебора удаляем элементы?
Мы говорим питону, перебирай от первого элемента до последнего, питон циклом извлекает элементы 1й, 2й, 3й, и тут казалось бы 4й, но! четвертый элемнт Вы удалили, и его место занял пятый! Питон об этом ничего не знает, он продолжает извлекать по индексу
Смотрите
1,2,3,4,5,6

мы удалили 4, какой элемент теперь будет пятым?
1,2,3,5,6
ШЕСТЬ
Ага, пятёрка вообще выпадает из перебора, потому что она была пятой, и цикл её показал бы на пятой 
иттерации, но она теперь стала четвертой и извлекается lst[4], но цикл то извлекает lst[5], а там у нас УЖЕ шестёрка
.

Не удаляйте элементы из списка в цикле. Никогда.




Отредактировано FishHook (Ноя. 16, 2013 12:44:43)

Офлайн

#3 Ноя. 16, 2013 16:38:18

soln
От:
Зарегистрирован: 2011-11-02
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

FishHook
Ну то есть классический цикл. Что же происходит, если мы в процессе перебора удаляем элементы?
Мы говорим питону, перебирай от первого элемента до последнего, питон циклом извлекает элементы 1й, 2й, 3й, и тут казалось бы 4й, но! четвертый элемнт Вы удалили, и его место занял пятый! Питон об этом ничего не знает, он продолжает извлекать по индексу
Смотрите
1,2,3,4,5,6
Да наверно Вы правы.
и это как раз объесняет по чему проход получается через один.
в случае
[a.pop(a.index(x)) for x in a]
FishHook
Не удаляйте элементы из списка в цикле. Никогда.

Это поняно. Если надо изменить список в цикле пользуюсь либо поверхносной копией либо copy.deepcopy



Отредактировано soln (Ноя. 16, 2013 16:39:08)

Офлайн

#4 Ноя. 16, 2013 16:56:18

FishHook
От:
Зарегистрирован: 2011-01-08
Сообщения: 8312
Репутация: +  568  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

soln
Это поняно. Если надо изменить список в цикле пользуюсь либо поверхносной копией либо copy.deepcopy
Да проще всё! Вместо того, чтобы удалять элементы, вы их просто не добавляйте. То есть мы делаем перебор по коллекции, и все элементы добавляем в другую коллекцию кроме тех, которые у нас “плохие”.
a = [1, 2, 3, 4]
a = filter(lambda x: x%2, a)
ну или фором или списковым выражением, как угодно, смысл в том, что сначала копировать, а потом фильтровать - глупо. Объедините фильтрацию и копирование в одну операцию.



Офлайн

#5 Ноя. 16, 2013 21:04:11

soln
От:
Зарегистрирован: 2011-11-02
Сообщения: 42
Репутация: +  0  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

FishHook
Вместо того, чтобы удалять элементы, вы их просто не добавляйте. То есть мы делаем перебор по коллекции, и все элементы добавляем в другую коллекцию кроме тех, которые у нас “плохие”.
Хм. Аведь и вправду. Спасибо.



Офлайн

#6 Ноя. 17, 2013 02:40:50

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

как устроен for или __iter__ ?

FishHook
Не удаляйте элементы из списка в цикле. Никогда.
Да можно удалять элементы вцикле, нет в этом ничего ужасного, просто двигаться по списку нужно от конца к началу.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version