Python 为什么这个用于排序异构序列的关键类行为异常?
Python3.x的函数不能用于对异构序列进行排序,因为大多数不同类型的对都是无序的(数值类型,如Python 为什么这个用于排序异构序列的关键类行为异常?,python,python-3.x,sorting,python-2.x,complex-numbers,Python,Python 3.x,Sorting,Python 2.x,Complex Numbers,Python3.x的函数不能用于对异构序列进行排序,因为大多数不同类型的对都是无序的(数值类型,如int,float,decimal.decimal等,属于例外): 为了在Python3.x中复制Python2.x的行为,我编写了一个类作为键参数用于sorted(),这取决于sorted()仅使用少于比较的事实: class motley: def __init__(self, value): self.value = value def __lt__(sel
int
,float
,decimal.decimal
等,属于例外):
为了在Python3.x中复制Python2.x的行为,我编写了一个类作为键
参数用于sorted()
,这取决于sorted()
仅使用少于比较的事实:
class motley:
def __init__(self, value):
self.value = value
def __lt__(self, other):
try:
return self.value < other.value
except TypeError:
return repr(type(self.value)) < repr(type(other.value))
到目前为止,一切顺利
然而,我注意到当使用包含复数的特定序列调用排序(s,key=motley)
时,出现了一种令人惊讶的行为:
>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
[(1+0j), 0.0, False, (2+3j), 1]
我希望0.0
、False
和1
在一组中(因为它们可以相互排序),而(1+0j)
和(2+3j)
在另一组中(因为它们属于同一类型)。这个结果中的复数不仅彼此分离,而且其中的一个坐在一组彼此比较但不与之相伴的对象的中间,这有点令人困惑。
这里发生了什么?您不知道比较是按什么顺序进行的,甚至不知道比较了哪些项目,这意味着您无法真正知道您的
\ult\uu
将产生什么影响。您定义的\uu lt\uuu
有时取决于实际值,有时取决于类型的字符串表示形式,但在排序过程中,两个版本可能用于同一对象。这意味着您的顺序不仅由列表中的对象决定,还可能取决于它们的初始顺序。这反过来意味着,仅仅因为对象是相互可比的,并不意味着它们将被分类在一起;它们可能被它们之间不可比较的对象“阻挡”
您可以通过放入一些调试打印来了解正在进行的操作,以查看其比较结果:
class motley:
def __init__(self, value):
self.value = value
def __lt__(self, other):
fallback = False
try:
result = self.value < other.value
except TypeError:
fallback = True
result = repr(type(self.value)) < repr(type(other.value))
symbol = "<" if result else ">"
print(self.value, symbol, other.value, end="")
if fallback:
print(" -- because", repr(type(self.value)), symbol, repr(type(other.value)))
else:
print()
return result
(因为
'float'
:-)我不确定,但您所描述的也可能是Python排序算法应该是稳定的,因为它不会对已经排序的序列重新排序。看,嘿。。。是的,a
循环确实扼杀了整个方法,不是吗?谢谢你的详细回答:-)我想你可能有兴趣知道我已经发布了一个。。。
>>> sorted(["one", 2.3, "four", -5], key=motley)
[-5, 2.3, 'four', 'one']
>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
[(1+0j), 0.0, False, (2+3j), 1]
class motley:
def __init__(self, value):
self.value = value
def __lt__(self, other):
fallback = False
try:
result = self.value < other.value
except TypeError:
fallback = True
result = repr(type(self.value)) < repr(type(other.value))
symbol = "<" if result else ">"
print(self.value, symbol, other.value, end="")
if fallback:
print(" -- because", repr(type(self.value)), symbol, repr(type(other.value)))
else:
print()
return result
>>> sorted([0.0, 1, (1+0j), False, (2+3j)], key=motley)
1 > 0.0
(1+0j) < 1 -- because <class 'complex'> < <class 'int'>
(1+0j) < 1 -- because <class 'complex'> < <class 'int'>
(1+0j) < 0.0 -- because <class 'complex'> < <class 'float'>
False > 0.0
False < 1
(2+3j) > False -- because <class 'complex'> > <class 'bool'>
(2+3j) < 1 -- because <class 'complex'> < <class 'int'>
[(1+0j), 0.0, False, (2+3j), 1]
>>> motley(1.0) < motley(lambda: 1) < motley(0) < motley(1.0)
True