【问题标题】:Python dictionaries are not allowed to change size but lists are?Python字典不允许改变大小,但列表是?
【发布时间】:2020-11-13 14:23:05
【问题描述】:

我想我刚刚在 Python 中发现了一个问题。

看看下面的代码:

a = {'a':1, 'b':2, 'c':3}

for i in a.values():
    if i == 2:
        a['d'] = 4
        
print(a)

这将导致运行时错误:

Traceback (most recent call last):
  File "<string>", line 4, in <module>
RuntimeError: dictionary changed size during iteration

我来自 Java 背景所以在迭代数据结构时实际上无法修改数据结构是有道理的。

但是当您看到以下代码对列表正常工作时,这个逻辑就崩溃了:

a = [1,2,3,4]

for i in iter(a):
    if i == 2:
        a.extend([5,6,7])
        
print(a)

代码按预期输出:

[1, 2, 3, 4, 5, 6, 7]

为什么这对列表有效,但对字典无效?

这毫无意义。

我知道dict.values()dict.items()dict.keys() 都返回迭代器但列表也是如此。

这段代码使用了迭代器,对吧?

a = [1,2,3,4]

for i in iter(a):
    if i == 2:
        a.extend([5,6,7])
        
print(a)

如果我错了,请纠正我。

我确实检查了this answer,但我没有得到具体的答案。

为什么要对字典进行特殊处理?

我在这里遗漏了一些非常基本的东西吗?

【问题讨论】:

  • for x in a 不是迭代器,其中任何一个都不是标准的一部分。在 Python 的其他实现中,您可能会得到不同的结果
  • @Marat 现在检查我的代码。我专门使用带有列表的迭代器。
  • 第二部分仍然有效,这是一个未定义的行为。这不是语言设计的有意部分
  • "我知道 dict.values()、dict.items()、dict.keys() 都返回迭代器...." 不,技术上是 they return views
  • FWIW, iter(a) 不需要重现相同的行为。

标签: python dictionary iterator


【解决方案1】:

这样做可以轻松避免这种情况

a = {'a' : 1, 'b' : 2, 'c' : 3}
for i in list(a.values()):
    if i == 2:
        a['d'] = 4
print(a)

至于为什么不同的处理我不知道,但只要你不遍历字典本身它就可以工作

【讨论】:

  • 我不想避免它。我想知道为什么会这样。我不想要变通办法,我想要一个理由。否则语言设计不一致。
  • @ng.newbie 不一致的语言设计并不是 Python 独有的。我怀疑原因是dict 的迭代器与该字典的内部结构紧密绑定,无法实时处理更新。解决方法确实没有什么问题。
  • @MarkRansom 我怀疑这是因为字典过去是无序的。我无法想象在迭代无序集合时添加/删除项目,这将是不可预测/不可靠的。但是对于我已经做过很多次的列表(主要是附加)。
  • @ng.newbie 只有集合和字典是无序的,但是列表和元组是有序的
  • @ng.newbie 列出无序?我希望你在开玩笑:-)
【解决方案2】:

你有它倒退。特殊处理不是针对字典,特殊处理是针对列表。那是因为迭代一个变化的列表很简单——你保留一个整数来告诉你列表中的偏移量。每次尝试通过迭代器访问某个项目时,您都可以检查它是否仍在列表的范围内,如果不在则生成异常。

>>> a = [1]
>>> x = 2
>>> for i in a:
    print(i)
    if x < 10:
        a[0:0] = [x]
        x += 1

1
1
1
1
1
1
1
1
1
>>> a
[9, 8, 7, 6, 5, 4, 3, 2, 1]

【讨论】:

  • 我确实看到了对字典的特殊处理here。列表的特殊处理是什么/在哪里?
  • @StefanPochmann 我的意思是一般禁止修改您正在迭代的序列。这是基本情况,任何偏离它的地方都是特殊的。显然,数据结构的构造将决定您如何迭代它的机制,因此需要自定义代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
相关资源
最近更新 更多