Skip to content

popitem from UserDict in LIFO order #147957

Closed

Description

@Andrew5057

Feature or enhancement

Proposal:

collections.UserDict.popitem currently uses the collections.abc.MutableMapping default implementation, which pops items in the order of iter(self.data) and is thus FIFO:

from collections import UserDict

d = UserDict()
d['spam'] = 0
d['ham'] = 1
assert(d.popitem() == ('spam', 0))

This does not match dict.popitem, which has been guaranteed to pop LIFO since Python 3.7:

d = dict()
d['spam'] = 0
d['ham'] = 1
assert(d.popitem() == ('ham', 1))

Given that UserDict is meant to "[simulate] a dictionary", it seems preferable for UserDict instances to pop LIFO as well. (This has already been the subject of confusion, per a recent Stack Overflow question.) This change could be a CPython implementation detail, but it could (in the long run) be a spec guarantee as well.

The spec has not historically guaranteed an order for UserDict.popitem, nor for MutableMapping.popitem (nor specified that UserDict is a subclass of MutableMapping), but this change might break programs that relied on the FIFO behavior anyways. That said, the whole point of UserDict is to emulate dict for subclassing purposes, so I think the consistency still outweighs the risk.

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

Linked PRs

Activity

  1. added a commit that references this issue on Apr 1, 2026
  2. self-assigned this
    on Apr 1, 2026
  3. rhettinger commented on Apr 1, 2026

    @rhettinger
    Contributor

    Neither UserDict, nor MutableMapping makes an ordering guarantee:

    >>> help(UserDict.popitem)
    Help on function popitem in module collections.abc:
    
    popitem(self)
        D.popitem() -> (k, v), remove and return **some** (key, value) pair
        as a 2-tuple; but raise KeyError if D is empty.
    
  4. Andrew5057 commented on Apr 1, 2026

    @Andrew5057
    ContributorAuthor

    @rhettinger The "some" note is based on the MutableMapping implementation. UserDict just doesn't have an implementation at all. However, dict makes the ordering guarantee; those using UserDict as an alternative to subclassing dict will likely expect that behavior.

  5. Andrew5057 commented on Apr 1, 2026

    @Andrew5057
    ContributorAuthor

    Is this a duplicate of gh-88913?

  6. added
    stdlibStandard Library Python modules in the Lib/ directory
    on Apr 1, 2026
  7. serhiy-storchaka commented on Apr 1, 2026

    @serhiy-storchaka
    Member

    This is an interesting question. UserDict inherits implementation from MutableMapping, but implements some methods by delegating to the underlying dict (because they are abstract in MutableMapping or for performance). What other methods are inherited from MutableMapping and not delegated to dict? What other methods are worth to delegate? The same questions for UserList and UserString.

  8. rhettinger commented on Apr 3, 2026

    @rhettinger
    Contributor

    @Andrew5057 The "some" note was mentioned not as a restriction, but as freedom to proceed with your change.

    Since the underlying dict is assignable, it can be anything. So, the docstring for the new popitem should be worded to say that it accesses entries in the same order as the underlying dict. In the case of a real dict (the normal case), it would be LIFO.

  9. added
    triagedThe issue has been accepted as valid by a triager.
    on Apr 3, 2026
  10. added a commit that references this issue on Apr 3, 2026
  11. added a commit that references this issue on Apr 15, 2026
  12. added a commit that references this issue on Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

stdlibStandard Library Python modules in the Lib/ directorytriagedThe issue has been accepted as valid by a triager.type-featureA feature request or enhancement

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions