Я пытаюсь воспроизвести (и, если возможно, улучшить) поведение сортировки Python 2.x в 3.x, чтобы взаимно упорядочиваемые типы, такие как int
, float
и т.д., Сортировались, как ожидается, и взаимно неупорядоченные типы группировались в выходных данных.
Вот пример того, о чем я говорю:
>>> sorted([0, 'one', 2.3, 'four', -5]) # Python 2.x
[-5, 0, 2.3, 'four', 'one']
>>> sorted([0, 'one', 2.3, 'four', -5]) # Python 3.x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() < int()
Моя предыдущая попытка использовать класс для параметра key для sorted()
(см. Почему этот класс ключей для сортировки гетерогенных последовательностей ведет себя странно?) В корне не работает, потому что его подход
- Пытаясь сравнить значения, и
- Если это не удается, возвращаясь к сравнению строкового представления их типов
может привести к непереходному порядку, как объяснил BrenBarn отличный ответ.
Наивный подход, который я изначально отверг, даже не пытаясь его кодировать, заключался бы в использовании ключевой функции, которая возвращает кортеж (type, value)
:
def motley(value):
return repr(type(value)), value
Тем не менее, это не делает то, что я хочу. Во-первых, это нарушает естественное упорядочение взаимно упорядоченных типов:
>>> sorted([0, 123.4, 5, -6, 7.89])
[-6, 0, 5, 7.89, 123.4]
>>> sorted([0, 123.4, 5, -6, 7.89], key=motley)
[7.89, 123.4, -6, 0, 5]
Во-вторых, возникает исключение, когда входные данные содержат два объекта одного и того же по сути неупорядоченного типа:
>>> sorted([{1:2}, {3:4}], key=motley)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()
... что по общему признанию является стандартным поведением в Python 2.x и 3.x - но в идеале я хотел бы, чтобы такие типы были сгруппированы вместе (меня не особенно заботит их упорядочение, но это, похоже, соответствует Python гарантирует стабильную сортировку, что они сохраняют свой первоначальный порядок).
Я могу обойти первую из этих проблем для числовых типов, выделив их специальным регистром:
from numbers import Real
from decimal import Decimal
def motley(value):
numeric = Real, Decimal
if isinstance(value, numeric):
typeinfo = numeric
else:
typeinfo = type(value)
return repr(typeinfo), value
... который работает, насколько это возможно:
>>> sorted([0, 'one', 2.3, 'four', -5], key=motley)
[-5, 0, 2.3, 'four', 'one']
... но не учитывает тот факт, что могут существовать другие различные (возможно, определяемые пользователем) типы, которые взаимно упорядочены, и, конечно, все еще терпят неудачу с внутренне неупорядоченными типами
>>> sorted([{1:2}, {3:4}], key=motley)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: dict() < dict()
Есть ли другой подход, который решает как проблему произвольных, различимых, но взаимно-упорядоченных типов, так и проблему изначально неупорядоченных типов?