PySide2代码Python2运行正常Python3报unhashable type: 'ListWidgetItem'错误
错误产生原因
PySide2信号连接绑定实例方法时,内部会将槽函数所属的实例作为键存入字典,用于管理连接生命周期(比如实例销毁时自动断开连接),该操作需要对实例做哈希计算。
- Python2环境下,自定义类如果没有显式定义
__hash__方法,会默认使用实例的内存id作为哈希值,因此就算QListWidgetItem本身未实现哈希逻辑,也能正常运算不报错。 - Python3环境规则不同:如果一个类显式实现了
__eq__方法但未实现__hash__方法,__hash__会被自动设为None,实例变为不可哈希类型。QListWidgetItem的Qt绑定已经实现了__eq__用于项的相等判断,但未实现__hash__,因此在Python3中作为字典键时就会触发不可哈希的报错。
可行解决方案
以下三种方案均可解决该问题,按侵入性从低到高排序:
方案1:用lambda/partial包装槽函数
不需要修改原有类定义,仅修改信号连接逻辑,避免直接绑定实例方法触发哈希计算:
# 用lambda包装 widget.resized.connect(lambda width, height: item.resize_to_widget_size(width, height)) # 或者用functools.partial from functools import partial widget.resized.connect(partial(item.resize_to_widget_size))
方案2:给自定义ListWidgetItem类添加哈希方法
显式指定用实例内存id作为哈希值,符合唯一标识的需求:
class ListWidgetItem(QtWidgets.QListWidgetItem): def __init__(self): super(ListWidgetItem, self).__init__() # 新增__hash__方法 def __hash__(self): return id(self) def resize_to_widget_size(self, width, height): self.setSizeHint(QtCore.QSize(width, height))
修改后原有的信号连接代码不需要改动即可正常运行。
方案3:将槽函数所属实例改为继承QObject的可哈希类型
如果有其他相关需求,可以把业务逻辑放到继承自QObject的类中实现,QObject的实例默认在Python3环境下可哈希,不过该方案改动量较大,适合重构场景使用。
内容的提问来源于stack exchange,提问作者filmguy
相关产品推荐
相关产品推荐

