Словарь бесконечный цикл выхода неожиданно

Вопрос задан: 1 год назад Последняя активность: 7 месяцев назад
up 42 down

Я экспериментировал с различными способами создания бесконечного цикла в Python (кроме обычного while True), И пришел с этой идеей:

x = {0: None}

for i in x:
    del x[i]
    x[i+1] = None  # Value doesn't matter, so I set it to None
    print(i)

На бумаге, я начертил путь это будет бесконечно цикл:

  1. Я Переберите значение этого ключа в словаре
  2. Я удалить эту запись.
  3. Текущее положение счетчика в цикле + 1 будет новый ключ со значением None который обновляет словарь.
  4. Я выходной ток счетчика.

Это, в моей голове, должен вывести натуральные числа в какой-то бесконечной моды петли:

0
1
2
3
4
5
.
.
.

Я думал, что эта идея была умна, но когда я запускаю его на Python 3.6, она выводит:

0
1
2
3
4

Да, это как-то остановился после 5 итераций. Очевидно, что нет базы условия или значения сторожевого в блоке коды цикла, так почему Python только работает этот код в 5 раз?

4 ответа

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

Реклама

up 43 down accepted

Там нет никакой гарантии, что вы будете перебирать все ваши записи Dict если вы мутировать его в петле. Из документы:

Итерация взгляды при добавлении или удалении записей в словаре может   поднять RuntimeError или не перебирать все записи.

Вы могли бы создать «перечисленный» бесконечный цикл, похожий на вашу первую попытку с помощью itertools.count(). Например:

from itertools import count

for i in count():
    print(i)
    # don't run this without some mechanism to break the loop, i.e.
    # if i == 10:
    #     break

# OUTPUT
# 0
# 1
# 2
# ...and so on
up 8 down

В этом случае, как @benvc писал, это не гарантируется. Но в случае, если вам интересно, почему это работает в C-Python:

Реализация C-Python уничтожает объект Dict после некоторых вставок и копирует его в новое место в памяти. Он не заботится о удалениях. Так что, когда это происходит, то цикл замечает это и разрыв с исключением.

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

https://github.com/satwikkansal/wtfpython#-modifying-a-dictionary-while-iterating-over-it

up 5 down

Я просто проверял свой код в python2 и Python3

python3 output
0,1,2,3,4
python2
0,1,2,3,4,5,6,7

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

RuntimeError: dictionary changed size during iteration

Так питон создает достаточно памяти для этого ключевого значения и еще несколько раз, и он будет израсходован, что нет никакого больше памяти не выделяется для словаря.

up 3 down

Как многие отмечали, изменение структуры данных во время итерации с for цикл не является хорошей идеей. while цикл, хотя действительно позволяет, что, как он повторно вычисляет условие цикла на каждой итерации (я впечатлен никто не предполагал, что в качестве альтернативы пока). Нужно просто найти условие правильного контура. Ваш сценарий должен был бы стать:

x = {0: None}
while x:
    i, _ = x.popitem()
    print(i)
    # to avoid infinite loop while testing
    # if i == 10:
    #     break
    x[i+1] = None

В Python, словарь является falsy, когда он пуст (см документы), Так что цикл остановится только тогда, когда в начале итерации x пустой. Поскольку словарь имеет только одну пару ключ-значение, popitem() должно быть достаточно, чтобы получить эту пару и удалить его из словаря. В ближайшее целое число, добавляется сразу после словаря опорожняется, условие цикла никогда не будет ложным, когда оценивается, таким образом, в результате чего в бесконечном цикле.

Ошибка 505

Что-то пошло не так

Попробуйте воспользоваться поиском