Does a Python dict preserve insert order?

This is the answer to "Does a Python dict preserve insert order?".

It depends on the version you use, but there is good news and the future looks bright:

Python 3.6 - built-in dict respects insert order

Good news!

A short interactive session with Python 3.6.0 released 2016-DEC-23:

$ python3.6
Python 3.6.0 (default, Jan  3 2017, 14:20:13) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.42.1)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> d = dict(foo=1, bar=2, baz=3)

Iterate over items:

>>> for k, v in d.items():
...     print(k, "->", v)
... 
foo -> 1
bar -> 2
baz -> 3

Update a key's value:

>>> d['foo'] = 42

Iterate again to show, update preserves position:

>>> for k, v in d.items():
...     print(k, "->", v)
... 
foo -> 42
bar -> 2
baz -> 3

Delete the key (position now inherited from next!):

>>> del d['foo']
>>> for k, v in d.items():
...     print(k, "->", v)
... 
bar -> 2
baz -> 3

Insert removed key again with some value:

>>> d['foo'] = -1

But that became appended to existing keys (insert order):

>>> for k, v in d.items():
...     print(k, "->", v)
... 
bar -> 2
baz -> 3
foo -> -1

Define some function with keyword args for fun:

>>> def called(pos, *args, **kwargs):
...     """Pull out what is in kwargs ..."""
...     for k, v in kwargs.items():
...             print(k, "->", v)
...

Call it with our dict unpacked (**d here equal to bar=2, baz=3, foo=-1):

>>> called(True, **d)
bar -> 2
baz -> 3
foo -> -1

Use cases like "Question: Sort a Python dictionary by value" now have simple solutions.

Sample:

  • Mapping pairs retrieved from a database

    • With unique string ids as keys and numeric values as values
  • Into a built-in Python version 3.6+ dict

Should now respect the insert order.

Given the resulting 2 column table expression from a database query like:

SELECT a_key, a_value FROM a_table ORDER BY a_value;

Stored in two python tuples k_seq and v_seq. Aligned by numerical index and with the same length of course.

Then:

k_seq = ('foo', 'bar', 'baz')
v_seq = (0, 1, 42)
ordered_map = dict(zip(k_seq, v_seq))

Allow to output later as:

for k, v in ordered_map.items():
    print(k, v)

Yielding in this case (for the new python 3.6+ built-in dict!):

foo 0
bar 1
baz 42

In the same ordering per value of v (if that determined the insertion order.

Where in the python 3.5 install on some machine it may yield:

bar 1
foo 0
baz 42

Details:

Hopefully this will lead to a thin layer OrderedDict implementation as a first step. Some StackOverflow users indicated, that they see use cases for the OrderedDict type also in the future.
I think the Python community at large will carefully inspect, if this will stand the test of time, and what the next steps will be.

Time to rethink our coding habits to not miss the possibilities opened by stable ordering of:

  • keyword arguments and
  • (intermediate) dict storage

The first because it eases dispatch in the implementation of functions and methods in some cases.

The second as it encourages to more easily use dict's as intermediate storage in processing pipelines.

Caveat Emptor:

This is a fresh feature:

"The order-preserving aspect of this new implementation is considered an implementation detail and should not be relied upon. [...] (this may change in the future, but it is desired to have this new dict implementation in the language for a few releases before changing the language spec to mandate order-preserving semantics for all current and future Python implementations; this also helps preserve backwards-compatibility with older versions of the language where random iteration order is still in effect, e.g. Python 3.5)."

But as in some human languages (e.g. German), usage shapes the language.

The will is now declared ... Python 3.6.0 has been released 2016-DEC-23.

Maybe this helps future coders to have one less pitfall, which currently is known as "Dictionaries are unordered" (in Python) e.g. as compared to C++, where std::map is a sorted associative container ... so we can unite on failing through not caring enough for the difference of "sorted by element order relation" vs. "insert sequence ordering" ;-)

results for ""

    No results matching ""