为啥 PySide 会从 Signals 的类成员中隐式创建对象成员?

Posted

技术标签:

【中文标题】为啥 PySide 会从 Signals 的类成员中隐式创建对象成员?【英文标题】:Why does PySide implicitely create object members from class members for Signals?为什么 PySide 会从 Signals 的类成员中隐式创建对象成员? 【发布时间】:2019-03-08 16:28:05 【问题描述】:

在PySide signals and slots page 上它说:“信号是实例拥有的运行时对象,它们不是类属性”。显然,QObject 构造函数在类属性中查找信号并将它们复制到对象实例。我的测试程序证实了这一点。

从 PySide 导入 QtCore

class Klass(QtCore.QObject):
    lst = []
    sig = QtCore.Signal(str)

def main():
    obj1 = Klass()
    obj2 = Klass()

    print "id: obj1.lst  = , obj1.sig  = ".format(id(obj1.lst),  id(obj1.sig))
    print "id: obj2.lst  = , obj2.sig  = ".format(id(obj2.lst),  id(obj2.sig))
    print "id: klass.lst = , klass.sig = ".format(id(Klass.lst), id(Klass.sig))

if __name__ == '__main__':
    main()

在我的输出中,您可以看到现在有三个信号对象,而对象和类的 lst-member 的 id 相同。

id: obj1.lst  = 4317739344, obj1.sig  = 4297560376
id: obj2.lst  = 4317739344, obj2.sig  = 4297560400
id: klass.lst = 4317739344, klass.sig = 4317851072

隐式创建对象属性只会令人困惑,因此风格不好(恕我直言)。也许他们确实有充分的理由,但我没有看到他们。所以我的问题是:他们为什么选择这个解决方案而不是仅仅在构造函数中将信号创建为常规属性?

【问题讨论】:

【参考方案1】:

它们不是副本。如果你检查它们的类型,你会看到类属性是PySide.QtCore.Signal,实例属性是PySide.QtCore.SignalInstance

print "type(obj1.sig): ".format(type(obj1.sig))
print "type(obj2.sig): ".format(type(obj2.sig))
print "type(Klass.sig): ".format(type(Klass.sig))

# type(obj1.sig): <type 'PySide.QtCore.SignalInstance'>
# type(obj2.sig): <type 'PySide.QtCore.SignalInstance'>
# type(Klass.sig): <type 'PySide.QtCore.Signal'>

这是必要的,因为 Qt 定义信号的方式。 Qt 使用Meta-Object System 来注册信号/槽。为了完成这项工作,PySide 在幕后做了一些“魔术”,将您的自定义类属性信号注册到元对象系统,并返回一个与实例属性同名的可用信号 (SignalInstance)。

原来的Signal 仍然存在,但被实例属性覆盖:

print "obj1.sig -> type: , id: ".format(type(obj1.sig), id(obj1.sig))
print "obj1.__class__.sig -> type: , id: ".format(type(obj1.__class__.sig), id(obj1.__class__.sig))
print "Klass.sig -> type: , id: ".format(type(Klass.sig), id(Klass.sig))

# obj1.sig -> type: <type 'PySide.QtCore.SignalInstance'>, id: 40629904
# obj1.__class__.sig -> type: <type 'PySide.QtCore.Signal'>, id: 41556352
# Klass.sig -> type: <type 'PySide.QtCore.Signal'>, id: 41556352

【讨论】:

以上是关于为啥 PySide 会从 Signals 的类成员中隐式创建对象成员?的主要内容,如果未能解决你的问题,请参考以下文章

为啥未使用的成员模板函数的类模板实例化失败

为啥受保护的实例成员在不同包的子类中不可见,但受保护的类成员是? [复制]

在 Java 中,为啥可以从同一个包中的类外部访问受保护的成员? [复制]

为啥我没有收到关于在 C# 8 中使用结构的类成员可能取消引用 null 的警告?

为啥派生类的朋友不能使用受保护的成员?

为啥在 pyside2 中,不能使用 QTranform mul QPointF?