字典无限循环意外退出

Sur*_*ari 42 python dictionary infinite-loop

我正在尝试在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)
Run Code Online (Sandbox Code Playgroud)

在纸面上,我找到了无限循环的方式:

  1. 我遍历字典中的键值
  2. 我删除了那个条目.
  3. 循环中的当前计数器位置+ 1将是具有None更新字典的值的新键.
  4. 我输出当前的计数器.

在我看来,这应该以一种无限循环的方式输出自然数:

0
1
2
3
4
5
.
.
.
Run Code Online (Sandbox Code Playgroud)

我认为这个想法很聪明,但是当我在Python 3.6上运行时,它会输出:

0
1
2
3
4
Run Code Online (Sandbox Code Playgroud)

是的,它在5次迭代后以某种方式停止了.显然,循环的代码块中没有基本条件或标记值,那么为什么Python只运行此代码5次?

ben*_*nvc 43

如果你在循环中改变它,则无法保证迭代所有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
Run Code Online (Sandbox Code Playgroud)

  • @SurajKothari - 添加了示例以防其他人最终查看您的问题,以便生成"枚举"无限循环(或者更有用的是一个不确定的循环,其中断点由运行时的某些其他操作确定)类似于您的初始尝试. (4认同)

HWM*_*ker 8

在这种情况下,像@benvc写的那样,这不能保证有效.但是如果你想知道为什么它在C-Python中有效:

一些插入后,C-Python实现会销毁dict对象并将其复制到内存中的新空间.它不关心删除.因此,当发生这种情况时,循环会注意到它并以异常为中断.

如果你想在这里阅读更多关于这个以及许多其他有趣的python内部的信息,请查看此链接.

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


小智 5

我刚刚在python2和python3中测试了你的代码

python3 output
0,1,2,3,4
python2
0,1,2,3,4,5,6,7
Run Code Online (Sandbox Code Playgroud)

有一件事可能会发生.当您创建第一个键值时,字典中只分配了一定量的内存,当您删除键值时,我们不会分配任何内存或释放内存,而只是删除值.一旦使用了所有分配的内存,它就会退出.因为如果你在没有del的情况下运行,你将收到此错误

RuntimeError: dictionary changed size during iteration
Run Code Online (Sandbox Code Playgroud)

因此python为该键值创建了足够的内存以及更多内存,一旦用完,就不再为字典分配内存.

  • 我只是测试了它,也许你有相反的版本.Python 2.7给出(0到7),Python 3给出(0到4) (2认同)