QStandardItem缺少__hash__方法

时间:2017-12-11 09:20:50

标签: python qt hash pyqt qstandarditem

我发现在将一些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__的一个简单版本(我已经完成了)。但是我有什么遗失的吗?

1 个答案:

答案 0 :(得分:1)

在Qt中,有三个requirements for hashability

  1. 类型必须是可分配的数据类型
  2. 该类型必须定义==运算符
  3. 必须为类型
  4. 定义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)