PyQt的pyqtProperty与Python内置property的区别及相关问题咨询
1 pyqtProperty与Python原生property的差异及适用场景
pyqtProperty是PyQt为对接Qt元对象系统设计的描述器,和原生property的核心差异是是否会被Qt的元系统识别:
- 独有优势:
- 可在Qt的全链路功能中使用:包括QML属性绑定、Qt Designer自定义控件属性面板、QSS样式表属性调用、
QObject.setProperty()/QObject.property()动态读写 - 支持绑定notify信号:属性值变更时自动触发指定信号,无需自己写触发逻辑,适合做界面数据双向绑定
- 强类型校验:声明时指定的返回类型会被Qt做类型校验,避免跨语言调用时的类型不兼容问题
- 可在Qt的全链路功能中使用:包括QML属性绑定、Qt Designer自定义控件属性面板、QSS样式表属性调用、
- 适用场景:只有当你需要用到上述Qt特有的功能时才需要用pyqtProperty,如果只是纯Python层面的属性封装,用原生property就足够了
2 pyqtProperty的继承关系与帮助文档来源
pyqtProperty没有继承Python原生的property类,它是PyQt通过SIP工具封装Qt C++层Q_PROPERTY逻辑,单独实现的Python描述器类,MRO显示直接继承自object符合实际情况。
- 找不到源码是正常的:PyQt的核心逻辑都编译成了
.pyd二进制文件,你用的5.9.2属于较早版本,官方没有附带.pyi类型存根文件,自然看不到可读源码 - help信息和原生property相似的原因:PyQt开发团队为了降低用户学习成本,在实现pyqtProperty时直接参考了原生property的文档结构编写了
__doc__属性,所以和原生help输出高度相似,和Qt官方C++版的Q_PROPERTY文档有差异也很正常,二者面向的用户群体不同
3 QObject初始化时自动调用属性getter的原因
这个现象的触发点是你代码setupUi末尾调用的QtCore.QMetaObject.connectSlotsByName(MainWindow):
- 该函数的作用是按照
on_控件名_信号名的规则自动匹配连接槽函数,运行时会遍历当前QObject实例的所有属性、方法来做名称匹配,遍历属性时会调用getter读取属性值,所以会触发你写的打印逻辑 - 报错原因是初始化顺序问题:你在
setupUi执行完成后才给self._custom_property赋值,而setupUi里已经调用了connectSlotsByName触发了getter,此时_custom_property还不存在,就会抛出AttributeError - 普通Python类没有这个问题是因为没有Qt元对象系统主动遍历属性的逻辑,getter只有主动访问的时候才会被调用
- debug和release运行表现不同的原因:PyQt在非debug模式下会默认捕获属性读取时抛出的异常,返回空的默认值不会透传到Python层面,debug模式为了方便排查问题会直接抛出异常
- 简单修复方案:把
self._custom_property = 1的赋值逻辑放到super().__init__()之后、self.setupUi(self)之前即可
内容的提问来源于stack exchange,提问作者Diogo
相关产品推荐
相关产品推荐

