与PriorityQueue
相关的内容没有改变;改变的是与dict
相关的内容,以及更一般地排序没有自然顺序的对象。
问题在于您正在尝试对包含字典的两个元组进行排序,例如:
(3, 'SOME_TAG', {'some': 'type', 'of': 'data'})
元组按字典序进行比较,也就是先比较第一个元素,如果相等,则尝试比较第二个元素,如果相等,则尝试比较第三个元素,以此类推。
大多数情况下,第一或第二个元素将不同,因此您永远不需要比较第三个元素,所以一切都会很好。
但偶尔会出现像这样的两个值:
(3, 'SOME_TAG', {'some': 'type', 'of': 'data'})
(3, 'SOME_TAG', {'some': 'othertype', 'with': 'differentdata'})
然后,它需要比较这两个字典以决定哪个元组较小。
这是没有意义的事情。字典项本质上是无序的,那么你如何决定哪一个比另一个小呢?事实上,即使字典项中有一个固定和可预测的元素,你期望的规则是什么呢?是第一个较小,因为 'of' < 'with'
吗?还是第一个更大,因为 'other type' < 'type'
吗?或者……?
Python 2.x 只会执行任意且无用的操作;而 Python 3.x 则会引发异常。在“Python 3.x 的新特性”文档的排序比较下有记录:
当操作数没有自然有意义的排序时,排序比较运算符(<
、<=
、>=
、>
)会引发 TypeError
异常。
因此,在这些情况下,你已经遇到了问题,但是 Python 2.x 通过时而自动执行无用的操作来隐藏问题,而 3.x 则使问题明显。
那么,解决方案是什么呢?你实际想要发生什么?我猜你实际上想要按照第一个元素排序,忽略其他元素。在这种情况下,你在 Python 2.x 中获得了自动接近该行为的结果,并且可能没有注意到有时它会以不可预测的方式不稳定。但如果你确实需要该行为,在两个版本中都必须自己编写。
不幸的是,与 Python 中大多数与排序相关的函数和对象不同,PriorityQueue
不接受 key
函数。* 这意味着你必须手动进行 "装饰-排序-取消装饰"。但这并不太难。例如:
class TupleSortingOn0(tuple):
def __lt__(self, rhs):
return self[0] < rhs[0]
def __gt__(self, rhs):
return self[0] > rhs[0]
def __le__(self, rhs):
return self[0] <= rhs[0]
def __ge__(self, rhs):
return self[0] >= rhs[0]
然后你可以这样做:
TX_Queue.put(TupleSortingOn0(3,'SOME_TAG',{some:type,of:data}))
* 因为它在内部使用
heapq
, 而
heapq
不能处理键,因为“在普通列表上工作的函数”的设计不允许它……