Python3的队列.PriorityQueue有哪些变化?

4
我正在将一款应用程序从py27迁移到py33。 大部分情况下都很简单。然而,在py27和py33之间,我有一个非常奇怪的区别。
我基本上有两个线程,它们通过队列进行通信。发送的数据类型如下:
TX_Queue.put((3,'SOME_TAG',{some:type,of:data}))
即,优先级、命令和数据。
在py27中,这运行得非常好,但是现在既然大部分转换到py33已经完成,偶尔会出现一个奇怪的异常:
return heappop(self.queue)
TypeError: unorderable types: dict() < dict()

你知道这是什么或者在py27和py3之间关于PriorityQueues有什么变化吗?

1个回答

10

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 不能处理键,因为“在普通列表上工作的函数”的设计不允许它……


那解释了变化发生的地方,谢谢。尽管你指出它有问题,但“旧方法”还是不错的。本质上,我使用PriorityQueue来确保某些信号跳过其他命令(通常是'STOP'),其余命令的顺序并不重要,只要它们在队列中即可。我实际上刚刚尝试了:(3,time.time(), 'SOME_TAG',{'some':'type','of':'data'}),希望提供一些可以排序的递增内容。这也失败了(可能有一个.put() 我漏掉了)。我会尝试你的排序方法。 - Naib
这也解决了我的Python2-Python3优先队列升级问题!现在我已经明白了Python2是如何以任意的方式处理这个问题的,我有一个后续问题。在这个修复/实现中,TupleSortingOn0如何处理0值相同/==的情况?队列是否会默认按照某种FIFO或其他标准排序进行排序?可能很明显,但我不确定-谢谢。 - 10mjg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接