Я на 99 +% все еще использую Python 2.x, но я стараюсь думать о том дне, когда я переключусь.
Итак, я знаю, что использование операторов сравнения (меньше / больше или равно) в гетерогенных типах, которые не имеют естественного упорядочения, больше не поддерживается в python3.x - вместо некоторых непротиворечивых (но произвольных) результат мы вместо этого поднимаем TypeError
. Я вижу в этом логику, и даже в основном считаю, что это хорошо. Последовательность и отказ от догадок - это добродетель.
Но что, если вы по сути хотите поведение python2.x? Какой лучший способ получить его?
Ради интереса (более или менее) я недавно внедрил Skip List , структуру данных, которая сохраняет свои элементы отсортированными. Я хотел использовать гетерогенные типы в качестве ключей в структуре данных, и мне нужно сравнивать ключи друг с другом, пока я прохожу структуру данных. Способ сравнения python2.x делает это действительно удобным - вы получаете понятное упорядочение среди элементов, которые имеют естественное упорядочение, и некоторые упорядочение среди тех, которые этого не делают.
Последовательное использование ключа сортировки / сравнения, такого как (type(obj).__name__, obj)
, имеет недостаток, заключающийся в том, что он не чередует объекты, которые имеют естественное упорядочение; все ваши float
сгруппированы вместе до того, как ваши int
с, а ваш str
полученный класс отделяется от ваших str
с.
Я придумал следующее:
import operator
def hetero_sort_key(obj):
cls = type(obj)
return (cls.__name__+'_'+cls.__module__, obj)
def make_hetero_comparitor(fn):
def comparator(a, b):
try:
return fn(a, b)
except TypeError:
return fn(hetero_sort_key(a), hetero_sort_key(b))
return comparator
hetero_lt = make_hetero_comparitor(operator.lt)
hetero_gt = make_hetero_comparitor(operator.gt)
hetero_le = make_hetero_comparitor(operator.le)
hetero_ge = make_hetero_comparitor(operator.gt)
Есть ли лучший способ?
Я подозреваю, что можно было бы построить угловой случай, который бы это испортил - ситуация, когда вы можете сравнить тип A с B и тип A с C, но где B и C повышают TypeError
по сравнению, и вы можете закончить с чем-то нелогичным, как a > b
, a < c
, и все же b > c
(из-за того, как сортируются их имена классов). Я не знаю, насколько вероятно, что вы столкнетесь с этим на практике.