Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the pyqtSignal() a class attribute, while it actually behaves as an instance attribute? [duplicate]

Tags:

signals

pyside

On the PySide signals and slots page it says: "Signals are runtime objects owned by instances, they are not class attributes". Apparently the QObject constructor looks in the class attributes for Signals and copies them to the object instance. This is confirmed by my test program.

from PySide import 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()

In my output you can see that there are now three signal objects whereas the id of lst-member is the same for both objects and the class.

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

Implicitly creating the object attributes is just confusing and therefore bad style (IMHO). Maybe they do have good reasons for this but I don't see them. So my question is: why did they choose this solution instead of just creating the signal as a regular attribute in the constructor?

like image 717
titusjan Avatar asked Feb 22 '13 13:02

titusjan


1 Answers

They are not copies. If you check the type of those, you'll see that the class attribute is PySide.QtCore.Signal and the instance attribute is 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'>

This is necessary because of the way Qt defines signals. Qt uses Meta-Object System to register signals/slots. In order to make this work, PySide does some 'magic' behind the curtain to register your custom class-attribute signal with Meta-Object System and return you a usable signal (SignalInstance) with the same name as instance attribute.

Original Signal is still there, but rather overridden with the instance attribute:

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
like image 72
Avaris Avatar answered Oct 13 '22 11:10

Avaris