UserDict.popitem不是后进先出

编程语言 2026-07-10

请看下面的代码片段:

from collections import UserDict

class D(dict): ...

d = D(foo="bar", baz=42)
print(d.popitem())  # ('baz', 42)

class UD(UserDict): ...

ud = UD(foo="bar", baz=42)
print(ud.data)  # {'foo': 'bar', 'baz': 42}
print(ud.popitem())  # ('foo', 'bar')

UserDict 实现中,顺序似乎如预期地被保持,因为它内部使用的是一个自Python 3.7起就已是有序的 data 字典。

为什么弹出的项是第一个而不是最后一个?我是不是理解错了?这是一个错误,还是一个特性?

在全新环境中测试了3.13.9和 3.14.0。

解决方案

UserDict 包装了一个字典,但它并没有继承 dict,甚至连 collections.OrderedDict 都不是子类。相反,它继承自 collections.abc.MutableMapping。因此,UserDict.popitem 不具备 dict.popitem 所具备的LIFO保证。在3.14及更早版本中,它改为使用 MutableMapping.popitem,该实现使用 dict.__iter__(因此是FIFO,只有在对值进行修改时才例外):

def popitem(self):
    '''D.popitem() -> (k, v), remove and return some (key, value) pair
       as a 2-tuple; but raise KeyError if D is empty.
    '''
    try:
        key = next(iter(self))
    except StopIteration:
        raise KeyError from None
    value = self[key]
    del self[key]
    return key, value

在3.15中,UserDict.popitem 将有一个 新的实现,它将保证与底层字典相同的删除顺序。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章