If your hash function is random (seeded), the order will be random over the seed.
d1 = dict()
d1['a'] = 1
d1['b'] = 1
print(d1.keys())
d2 = dict()
d2['a'] = 1
d2['b'] = 1
print(d2.keys())Seeded hashing was introduced to python 3.2.3: https://docs.python.org/3.3/using/cmdline.html#cmdoption-R
$ python3 --version
Python 3.5.2
$ python3 -c "print(hash('a'))"
6106879154137036349
$ python3 -c "print(hash('a'))"
9160572615033669802
$ python3 -c "print(set('abcdef'))"
{'d', 'f', 'e', 'b', 'c', 'a'}
$ python3 -c "print(set('abcdef'))"
{'e', 'f', 'd', 'a', 'b', 'c'}
Note that there is no guarantee that this ordering is uniformly random. (Though it probably is.) d1 is d2 ⇒ list(d1) == list(d2)
But the order is not guaranteed to be consistent between two equal dictionaries, in that d1 == d2 ⇏ list(d1) == list(d2)
This is because the history of the dictionary can affect its order, not just its contents. For example, x = {-1: (), -2: ()}
y = {-2: (), -1: ()}
list(x) != list(y)
This remains true, but now the particular order produced from a given list of insert and delete operations is well-defined, rather than arbitrary.It's worth noting that previously the order of two dictionaries with the same history was also the same (but may vary between program runs), but that was not guaranteed.
It's not actually clear if this is still regarded as an implementation detail, but I expect it will be effectively impossible to stop this becoming a key assumption of many libraries, so would expect any attempt to require OrderedDict (except for pre-3.6 compatibility) will fail.