Difference between dictionary and OrderedDict
As of Python 3.7, a new improvement to the dict
built-in is:
the insertion-order preservation nature of dict objects has been declared to be an official part of the Python language spec.
This means there is no real need for OrderedDict
anymore ð. They are almost the same.
Some minor details to consider...
Here are some comparisons between Python 3.7+ dict
and OrderedDict
:
from collections import OrderedDict
d = {'b': 1, 'a': 2}
od = OrderedDict([('b', 1), ('a', 2)])
# they are equal with content and order
assert d == od
assert list(d.items()) == list(od.items())
assert repr(dict(od)) == repr(d)
Obviously, there is a difference between the string representation of the two object, with the dict
object in more natural and compact form.
str(d) # {'b': 1, 'a': 2}
str(od) # OrderedDict([('b', 1), ('a', 2)])
As for different methods between the two, this question can be answered with set theory:
d_set = set(dir(d))
od_set = set(dir(od))
od_set.difference(d_set)
# {'__dict__', '__reversed__', 'move_to_end'} for Python 3.7
# {'__dict__', 'move_to_end'} for Python 3.8+
This means OrderedDict
has at most two features that dict
does not have built-in, but work-arounds are shown here:
Workaround for __reversed__
/ reversed()
No workaround is really needed for Python 3.8+, which fixed this issue. OrderedDict
can be "reversed", which simply reverses the keys (not the whole dictionary):
reversed(od) # <odict_iterator at 0x7fc03f119888>
list(reversed(od)) # ['a', 'b']
# with Python 3.7:
reversed(d) # TypeError: 'dict' object is not reversible
list(reversed(list(d.keys()))) # ['a', 'b']
# with Python 3.8+:
reversed(d) # <dict_reversekeyiterator at 0x16caf9d2a90>
list(reversed(d)) # ['a', 'b']
To properly reverse a whole dictionary using Python 3.7+:
dict(reversed(list(d.items()))) # {'a': 2, 'b': 1}
Workaround for move_to_end
OrderedDict
has a move_to_end
method, which is simple to implement:
od.move_to_end('b') # now it is: OrderedDict([('a', 2), ('b', 1)])
d['b'] = d.pop('b') # now it is: {'a': 2, 'b': 1}
Adding on to the answer by Brian, OrderedDict
is really great. Here's why:
You can use it as simple
dict
object because it supports equality testing with otherMapping
objects like collections.counter.OrderedDict
preserves the insertion order as explained by Brian. In addition to that it has a method popitem which returns (key,value) pairs in LIFO order. So, you can also use it as a mapped 'stack'.
You not only get the full features of a dict
but also, some cool tricks.
An OrderedDict
preserves the order elements were inserted:
>>> od = OrderedDict()
>>> od['c'] = 1
>>> od['b'] = 2
>>> od['a'] = 3
>>> od.items()
[('c', 1), ('b', 2), ('a', 3)]
>>> d = {}
>>> d['c'] = 1
>>> d['b'] = 2
>>> d['a'] = 3
>>> d.items()
[('a', 3), ('c', 1), ('b', 2)]
So an OrderedDict
does not order the elements for you, it preserves the order you give it.
If you want to "sort" a dictionary, you probably want
>>> sorted(d.items())
[('a', 1), ('b', 2), ('c', 3)]
Starting with CPython 3.6 and all other Python implementations starting with Python 3.7, the built-in dict
is ordered - you get the items out in the order you inserted them. Which makes dict
and OrderedDict
effectively the same.
The documentation for OrderedDict
lists the remaining differences. The most important one is that
- The equality operation for
OrderedDict
checks for matching order.
Then there's a few minor practical differences:
dict.popitem()
takes no arguments, whereasOrderedDict.popitem(last=True)
accepts an optionallast=
argument that lets you pop the first item instead of the last item.OrderedDict
has amove_to_end(key, last=True)
method to efficiently reposition an element to the end or the beginning. Withdict
s you can move a key to the end by re-inserting it:mydict['key'] = mydict.pop('key')
- Until Python 3.8, you could do
reversed(OrderedDict())
butreversed({})
would raise aTypeError: 'dict' object is not reversible
error because they forgot to add a__reversed__
dunder method todict
when they made it ordered. This is now fixed.
And there are a few under-the-hood differences that might mean that you could get better performance for some specific usecase with OrderedDict
:
- The regular
dict
was designed to be very good at mapping operations. Tracking insertion order was secondary. - The
OrderedDict
was designed to be good at reordering operations. Space efficiency, iteration speed, and the performance of update operations were secondary. - Algorithmically,
OrderedDict
can handle frequent reordering operations better thandict
. This makes it suitable for tracking recent accesses (for example in an LRU cache).
See this great talk from 2016 by Raymond Hettinger for details on how Python dictionaries are implemented.