我发现在将一些Python2 / Qt4代码转换为Python3 / Qt5时,显然QStandardItem不能再用作dict键,因为它没有实现__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作为dict键吗?
明显的解决方法是将QStandardItem子类化并重新实现__hash__
的一个简单版本(我已经完成了)。但是我有什么遗失的吗?
答案 0 :(得分:1)
在Qt中,有三个requirements for hashability:
==
运算符qHash
函数
醇>
因此,如果PyQt想要保持与Qt的一致性,它应该只在上述条件适用时定义__hash__
,并且它的实现应该只委托给Qt提供的任何qHash
函数。
将Python 2与PyQt4 / 5一起使用时的行为应该被认为是错误的,因为它给出的结果不与Qt一致。通过查看 可以使用的类型(以Qt术语表示)会发生什么情况可以看出这一点:
使用Python 3:
>>> a = QtCore.QUrl('foo.bar')
>>> b = QtCore.QUrl('foo.bar')
>>> a == b
True
>>> hash(a) == hash(b)
True
这正是我们想要的:比较相等的对象, hash 也应该相等。但现在看看在Python 2中使用相同版本的PyQt时会发生什么:
>>> a = Qt.QUrl('foo.bar')
>>> b = Qt.QUrl('foo.bar')
>>> a == b
True
>>> hash(a) == hash(b)
False
似乎像对象的身份这样的东西被Python 2中的__hash__
实现使用,显然它不会与Qt&#39保持一致; s哈希语义。
QStandardItem
类在Qt中从不可以清除,因此为了保持一致性,PyQt现在选择不为它提供__hash__
方法。而且由于QStandardItem
的实例实际上是可变的,因此PyQt非常合理地让用户决定何时定义__hash__
以及如何实现它。为了与Python 2兼容,这可能只返回id(self)
。