5

Consider the following snippet:

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')

The order seems to be preserved in the UserDict implementation as it should since it internally uses a data dict which is ordered since 3.7.

Why is the popped item the first one and not the last one? Am I misunderstanding something? Is this a bug or a feature?

Tested on 3.13.9 and 3.14.0 in fresh environments.

3
  • This actually seems like a bug to me. I'd report it on CPython github.. Commented Apr 1 at 3:34
  • For the record, there seems to be an easy workaround if you want LIFO: you can use ud.data.popitem() instead of ud.popitem(). Commented Apr 1 at 3:40
  • 2
    github.com/python/cpython/issues/88913 Commented Apr 1 at 7:07

1 Answer 1

4

UserDict wraps a dictionary, but it doesn't subclass dict or even collections.OrderedDict. Instead, it subclasses collections.abc.MutableMapping. As such, UserDict.popitem doesn't have the LIFO guarantees that dict.popitem does. In 3.14 and earlier, it instead uses MutableMapping.popitem, which is implemented using dict.__iter__ (and is thus FIFO, except for value mutations):

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

In 3.15, UserDict.popitem will have a new implementation that will guarantee the same removal order as the underyling dictionary.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

Draft saved
Draft discarded

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.