5

Why are dicts orderable in python2, but not in python3? I can't find it anywhere in the documentation.

Python 3.3.4 (default, Feb 11 2014, 16:14:21)
>>> sorted([{'a':'a'},{'b':'b'}])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()

vs.

Python 2.7.6 (default, Feb 26 2014, 12:01:28)
>>> sorted([{'a':'a'},{'b':'b'}])
[{'a': 'a'}, {'b': 'b'}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Matt Woelk
  • 1,940
  • 1
  • 20
  • 24
  • Nope, what order did you expect them to be in? – Martijn Pieters Mar 11 '14 at 18:24
  • 1
    Hrm, I was wrong, both keys and values are used; still, because dictionaries are *themselves* unordered, this doesn't actually make much sense. – Martijn Pieters Mar 11 '14 at 18:28
  • 1
    For a reference of what Python 2 does: [Is there a description of how cmp works for dict objects in Python 2?](http://stackoverflow.com/q/3484293) – Martijn Pieters Mar 11 '14 at 18:41
  • Why was that abandoned in Python 3? Is it found in some documentation somewhere? – Matt Woelk Mar 11 '14 at 18:42
  • Python 3 simplified ordering dramatically: http://docs.python.org/3/whatsnew/3.0.html#ordering-comparisons; `dict` never implemented `__lt__` or `__gt__`, etc.; only `__cmp__` was implemented (and `__eq__` and `__ne__`). – Martijn Pieters Mar 11 '14 at 18:43
  • 1
    But the ordering wasn't even documented, and doesn't make sense in all use-cases. Explicit is better than implicit; you need to sort dictionaries you need to bring your own definition what the proper order should be. – Martijn Pieters Mar 11 '14 at 18:47
  • This series of comments is the answer I was looking for. – Matt Woelk Mar 11 '14 at 18:57
  • Relevant: [`list.sort`](https://docs.python.org/3.7/library/stdtypes.html#list.sort). – 0 _ Dec 25 '17 at 12:12

2 Answers2

10

Python 2 uses an undocumented ordering, implemented as a .__cmp__() special method.

The ordering only makes sense in a limited set of use-cases, and only exists because Python 2 tries to make everything orderable.

Python 3 drastically cleaned up Python's ordering story; .__cmp__() is gone, and only types that actually have a natural ordering (such as numbers and strings) now support ordering. For everything else, you'll need to explicitly define an ordering.

Dictionaries do not have a natural ordering. If you do need to order dictionaries, you need to define an explicit order that makes sense for your use case. If that means comparing just the keys, do so (e.g. use key=sorted), etc.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • But why in python 3 can I sort a list of sets? If I do a = {1, 2}, b = {3, 4} I can do sorted([a, b]) and sorted([b, a]), but sorted([a, b]) != sorted([b, a]). This seems like it it using the len operator as a key, but why doesn't it throw a TypeError instead? – Erotemic Jun 08 '17 at 15:13
  • @Erotemic sets overload the comparison operator to implement subset testing instead. `a < b` is true if a is a strict subset of b. – Martijn Pieters Jun 08 '17 at 15:20
  • @Erotemic they don't define a sort order; `{1, 2, 3}` is a superset of sets `{1}`, `{2}`, and `{3}`, but those three smaller sets are not subsets of one another and so `<` returns false for any combination of those smaller sets. That breaks the expectations of sorting. No type error is thrown however because it is still a legal test. – Martijn Pieters Jun 08 '17 at 15:24
9

You'll need to sort with a key (documentation). Only you know what key you want, but here's one example:

>>> dicts = [{'a':'a'},{'b':'b'}]
>>> sorted(dicts, key=lambda x:sorted(x.keys()))
[{'a': 'a'}, {'b': 'b'}]

This is sorting by keys, where the dict with the "lowest" key comes first


Edit: as pointed out by Martijn Pieters, this answer describes exactly how Python 2 does it. But you should sort in the way that makes sense to your situation, which may be fundamentally different from how Python 2 does it.

Community
  • 1
  • 1
mhlester
  • 22,781
  • 10
  • 52
  • 75
  • Which is pretty much what Python 2 did except it also compared values if keys were equal. – Martijn Pieters Mar 11 '14 at 18:32
  • I linked to a detailed description from Ned in a [comment under the question](http://stackoverflow.com/questions/22333388/dicts-are-not-orderable-in-python-3/22333507?noredirect=1#comment33940961_22333388). – Martijn Pieters Mar 11 '14 at 18:46