Удаление элемента из итерации через него обычно приводит к исключению RuntimeError: dictionary changed size during iteration
:
d = {1: 2}
# exception raised
for k in d:
del d[k]
Чтобы быть более точным, само удаление удастся. Однако, чтобы ввести следующий раунд итерации, интерпретатор должен вызвать next(it)
, где it
является итератором через словарь, полученный ранее. В этот момент next()
заметит, что размер словаря изменился и жалуется.
Пока все хорошо. Но что, если мы удалим и добавим элемент в словарь:
d = {1: 1}
# no exception raised
for k in d:
# order of next two lines doesn't matter
d[k*10] = k*10
del d[k]
Я почти уверен, что это небезопасно (документы подразумевают, что во время итерации не допускается ни вставка, ни удаление). Почему интерпретатор разрешает запуск этого кода без ошибок?
Мое единственное предположение - слишком дорого проверить, какие итераторы недействительны всякий раз, когда вызывается метод вставки или удаления. Таким образом, dict
не пытается быть идеальным в создании этого исключения. Вместо этого он просто отслеживает размер словаря внутри каждого итератора и проверяет, что он не изменился всякий раз, когда итератору на самом деле предлагается перейти к следующему элементу. Нет ли подхода, который позволил бы полностью проверить достоверность по низкой цене?