This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ncoghlan
Recipients ncoghlan
Date 2013-06-09.13:54:32
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1370786072.61.0.824503392112.issue18173@psf.upfronthosting.co.za>
In-reply-to
Content
Armin Ronacher pointed out that one downside of the removal of implicit cross-type comparisons in Python 3 is that it makes it harder to produce a stable repr for mixed-type containers.

This seems like a valid point to me, so I propose adding a suitable "MixedTypeKey" definition to reprlib. Passing "key=reprlib.MixedTypeKey" would then reproduce the old Python 2. sorting behaviour.

We can actually improve on the Python 2 approach by basing the fallback comparison on fully qualified type names rather than on the type id.

Proposed implementation (see https://gist.github.com/ncoghlan/5743523):

>>> class MixedTypeKey:
...     """Sort key for mixed type lists in Python 3
... 
...     >>> sorted([None, ..., 1, 1j, "", (), {}, []])
...     Traceback (most recent call last):
...       File "<stdin>", line 1, in <module>
...     TypeError: unorderable types: ellipsis() < NoneType()
...     >>> sorted([None, ..., 1, 1j, "", (), {}, []], key=MixedTypeKey)
...     [None, Ellipsis, 1, 1j, '', (), {}, []]
...     """
...     def __init__(self, k):
...         self._sort_key = k
...         self._type_name = self._get_fully_qualified_name(k)
...     def _get_fully_qualified_name(self, k):
...         k_type = type(k)
...         # Use __qualname__ if available, __name__ otherwise
...         try:
...             k_name = k_type.__qualname__
...         except AttributeError:
...             k_name = k_type.__name__
...         return k_type.__module__ + "." + k_name
...     def __lt__(self, other):
...         # Try standard sorting first
...         sort_key = self._sort_key
...         try:
...             other_sort_key = other._sort_key
...         except AttributeError:
...             other_sort_key = other
...         try:
...             return sort_key < other_sort_key
...         except TypeError:
...             pass
...         # If that fails, sort by the fully qualified type names
...         try:
...             other_type_name = other._type_name
...         except AttributeError:
...             other_type_name = self._get_fully_qualified_name(other)
...         return self._type_name < other_type_name
... 
>>> sorted([None, ..., 1, 1j, "", (), {}, []])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: ellipsis() < NoneType()
>>> sorted([None, ..., 1, 1j, "", (), {}, []], key=MixedTypeKey)
[None, 1j, {}, Ellipsis, 1, [], '', ()]
>>> MixedTypeKey(None) < ...
True

The stdlib version could omit the fallback to __name__ (since it doesn't need to cope with old versions of Python)

Support for other comparisons could theoretically be added, but I advise against it without a solid use case (sorting only needs __lt__).
History
Date User Action Args
2013-06-09 13:54:32ncoghlansetrecipients: + ncoghlan
2013-06-09 13:54:32ncoghlansetmessageid: <1370786072.61.0.824503392112.issue18173@psf.upfronthosting.co.za>
2013-06-09 13:54:32ncoghlanlinkissue18173 messages
2013-06-09 13:54:32ncoghlancreate