Explain Codes LogoExplain Codes Logo

How to keep keys/values in same order as declared?

python
collections
dataframe
pandas
Nikita BarsukovbyNikita Barsukov·Feb 19, 2025
TLDR

Harness Python 3.7+ built-in dict to inherently retain the order of keys/values as they're introduced. For Python 3.6 and its predecessors, opt for the explicit order assured by collections.OrderedDict.

# Python 3.7+ my_dict = {'apple': 1, 'banana': 2} print(my_dict) # {'apple': 1, 'banana': 2} # Python 3.6 and before from collections import OrderedDict my_ordered_dict = OrderedDict([('apple', 1), ('banana', 2)]) # Like Jon Snow, order knows something. print(my_ordered_dict) # OrderedDict([('apple', 1), ('banana', 2)])

Diving in: Order preservation in Python dicts

From Python 3.7 onwards, standard dict pledges its loyalty to maintaining insertion order - it's enshrined in the language's DNA, not a mere lucky implementation fluke.

In Python 3.6, the preservation of order was a side effect of the implementation, however, it wasn't guaranteed by the language and feared getting axed in future versions. Python 3.7 confronts this fear, making this behavior official.

This shift is an outcome of an improved dict implementation, which led to lesser memory consumption with a compact internal representation and inadvertently preserved order. The users relished this order preservation so much that it became a permanent language feature.

Use cases for OrderedDict

Even with dict order conservation, there's a time and place for OrderedDict:

  • Backward harmony: When code needs to play nice with older Python versions (pre 3.7) the OrderedDict comes to the rescue, ensuring order preservation.
  • Explicit semantics: When readability is at stake, the usage of OrderedDict conveys that the order holds significance.
  • Extra functionality: Methods like popitem(last=True) (for FIFO dynamics) or popitem(last=False) (for LIFO dynamics) and move_to_end(), found in OrderedDict, are missing in the built-in dict.
from collections import OrderedDict # FIFO removal (Goodbye first!) fifo_dict = OrderedDict(one=1, two=2, three=3) first_in, _ = fifo_dict.popitem(last=False) print(f'First inserted: {first_in}') # LIFO removal (Later, last!) lifo_dict = OrderedDict(one=1, two=2, three=3) last_in, _ = lifo_dict.popitem() print(f'Last inserted: {last_in}')

Data buckets for ordered keys/values

While dictionaries are in the spotlight for key-value data storage, they were not traditionally optimized to maintain a fixed key/value order - a role ideally suited for arrays or lists. So consider striding towards list of tuples or even custom classes when the rigid order is a primary requirement of your code. But be aware - while lists charm you with order maintenance, dictionary-style constant time search won’t follow suit.

Practical scenarios with ordered dicts

Converting to and from dict and OrderedDict

Python 3.7+ allows you to convert a regular dict to an OrderedDict without playing with the order. But be wary of the other way round in versions before Python 3.7 – transforming an OrderedDict to a dict may jumble up the original order.

Going reverse with ordered dicts

Need to sail against the current? OrderedDict from collections supports reverse iteration using the reversed() function, allowing you to process entries in the opposite direction of their insertion – a unique functionality for maintaining order.

ordered = OrderedDict((f'item{i}', i) for i in range(5)) # Five items, eight legs, because JavaScript didn’t eat them. for item in reversed(ordered): print(item, ordered[item]) # Now that's a nice backflip!

Securing the order: fromkeys

Sometimes, you'll want to secure the order of keys, making them immune to modifications. A direct method to freeze the order isn't available in OrderedDict, but by using the fromkeys method, you can create a new OrderedDict with a definitive set of keys and a default value, effectively locking dow the order.

keys = ('apple', 'banana', 'cherry') # Fruit salad, anyone? frozen_dict = OrderedDict.fromkeys(keys, None) # Order served chill. print(frozen_dict) # Outputs OrderedDict([('apple', None), ('banana', None), ('cherry', None)])

Historical narratives and resources

For an enriched comprehension, check out Raymond Hettinger's enlightening posts and talks offering a deep dive into the Python 3.6+ dictionary implementation. For the old timers still working with Python 2.7, where OrderedDict initially surfaced, there are a multitude of recipes that can guide you on crafting ordered collections in earlier Python eras.