2016-07-17 3 views
1

Я видел решения и обходные пути, но не мог найти объяснения выбора, чтобы не изменять смены наборов во время итерации по ним. Можете ли вы помочь мне понять, почему это нормальноПочему я не могу изменить набор, который я повторяю?

In [1]: l = [1] 

In [2]: for i in l: 
      l.append(2*i) 
      if len(l)>10: 
        break 

In [3]: l 
Out[3]: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024] 

в то время как это не в порядке

In [4]: l = {1} 

In [5]: for i in l: 
      l.add(2*i) 
      if len(l)>10: 
        break 
--------------------------------------------------------------------------- 
RuntimeError        Traceback (most recent call last) 
<ipython-input-5-b5bdff4a382b> in <module>() 
----> 1 for i in l: 
     2   l.add(2*i) 
     3   if len(l)>10: 
     4     break 
     5 

RuntimeError: Set changed size during iteration 

Что плохого об изменении набора во время прохода?

Я знаю, что порядок в наборе не определен, поэтому next может быть затруднен. Это причина?

ответ

3

Набор поддерживается a хеш-таблица (см. Why is the order in Python dictionaries and sets arbitrary?). Записи в наборе помещаются в эту таблицу на основе их хэша, который, в свою очередь, определяет их порядок.

Добавление или удаление элементов в эту хеш-таблицу изменяет порядок итераций , иногда материально, так как таблица может быть изменена (где все существующие записи перерезаны на основе нового размера таблицы). Из-за этого итерация не может продолжаться в тот момент, когда набор был изменен; вы в противном случае могли бы снова увидеть одинаковые значения, даже в другом порядке.

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

+0

Вы уверены, что порядок итераций в списках определен, а не просто «выпадает из реализации» и может измениться? – Elazar

+0

@ Элазар: Да, я уверен. Списки имеют определенный порядок. Даже если вы вставили или удалили элементы, порядок все еще четко определен из одной манипуляции к следующей. –

0

Принудительное внедрение коллекции, позволяющей изменять, в то время как итерация ограничивает ее очень плохой производительностью. Подумайте о связанный список и простой итератор, который указывает на узел. Подумайте о том, что динамический массив расширяется и нуждается в перераспределить память, (хэш-таблицы, то есть осуществление dict и set, использует такой массив. list ы реализуются с помощью такого массива) и т.д.

0

Прежде всего вам нужно немного разобраться в how dicts work. Sets работают одинаково (с точки зрения хранения ключей) под обложками. Я не думаю, что я мог бы объяснить это лучше, чем Brandon Rhodes at PyCon (разговор на этот вопрос отвечает в какой-то момент и является феноменальной ссылкой для структур данных, лежащих в основе dicts и sets).

В принципе, для dicts//10 порядок итераций может меняться по мере добавления или удаления предметов. То же самое относится и к lists.

Смежные вопросы