QStandardItem缺少__hash__方法

4
我发现将一些Python2/Qt4代码转换为Python3/Qt5时,QStandardItem似乎不能再作为字典键使用,因为它没有实现__hash__,所以不再被视为不可变的。
以下是两个代码片段显示了这个问题:
PyQt4:
>>> from PyQt4 import QtGui
>>> a = QtGui.QStandardItem()
>>> b = {}
>>> b[a] = "1"
>>> a.__hash__()
2100390

PyQt5:

>>> from PyQt5 import QtGui
>>> a = QtGui.QStandardItem()
>>> b = {}
>>> b[a] = "1"
TypeError: unhashable type: 'QStandardItem'
>>> a.__hash__()
TypeError: 'NoneType' object is not callable

这个更改是为什么做的?我不应该使用QStandardItem作为字典键吗?

明显的解决方法是子类化QStandardItem并重新实现一个简单版本的__hash__(我已经这样做了)。但是我是否遗漏了什么?


也许可以在邮件列表上提问? - user3419537
1个回答

2
在Qt中,哈希化有三个要求
  1. 类型必须是可分配的数据类型
  2. 类型必须定义一个==运算符
  3. 必须为该类型定义一个qHash函数
因此,如果PyQt想要与Qt保持一致,只有在满足上述条件时才应该定义__hash__,并且其实现应该简单地委托给Qt提供的任何qHash函数。
在使用PyQt4/5和Python 2时的行为可能应该被认为是一个错误功能,因为它给出的结果与Qt不一致。这可以通过查看一个在Qt术语中是可哈希的类型发生的情况来看到:
在使用Python 3时:
>>> a = QtCore.QUrl('foo.bar')
>>> b = QtCore.QUrl('foo.bar')
>>> a == b
True
>>> hash(a) == hash(b)
True

这正是我们想要的:相互比较相等的对象应该具有相等的哈希值。但是,当使用相同版本的PyQt和Python 2时,情况会发生变化。
>>> a = Qt.QUrl('foo.bar')
>>> b = Qt.QUrl('foo.bar')
>>> a == b
True
>>> hash(a) == hash(b)
False

似乎Python 2中的__hash__实现使用了类似对象“identity”的东西,这显然与Qt的哈希语义永远不一致。在Qt中,QStandardItem类从来没有被哈希过,因此为了保持一致性,PyQt现在选择不为其提供__hash__方法。而且,由于QStandardItem的实例是可变的,PyQt非常合理地让用户决定何时定义__hash__以及如何实现它。为了与Python 2兼容,这可能只需返回id(self)即可。

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