Question

Pretty simple question. I've seen it mentioned in many places that using properties on an old-style class shouldn't work, but apparently Qt classes (through PyQt4) aren't new-style and there are properties on a few of them in the code I'm working with (and as far as I know the code isn't showing any sorts of problems)

I did run across a pyqtProperty function, but I can't seem to find any documentation about it. Would it be a good alternative in this instance?

Was it helpful?

Solution

property works because QObject has a metaclass that takes care of them. Witness this small variation on @quark's code...:

from PyQt4.QtCore import QObject

def makec(base):
  class X( base ):
      def __init__(self):
          self.__x = 10
      def get_x(self):
          print 'getting',
          return self.__x
      def set_x(self, x):
          print 'setting', x
          self.__x = x
      x = property(get_x, set_x)

  print 'made class of mcl', type(X), issubclass(type(X), type)
  return X

class old: pass
for base in (QObject, old):
  X = makec(base)
  x = X()
  print x.x # Should be 10
  x.x = 30
  print x.x # Should be 30

running this emits:

made class of mcl <type 'PyQt4.QtCore.pyqtWrapperType'> True
getting 10
setting 30
getting 30
made class of mcl <type 'classobj'> False
getting 10
30

see the difference? In the class that's really a legacy (old-type) class, the one made the second time, metaclass is classobj (which ISN'T a subclass of type) and properties don't work right (assigning x.x bypasses the property, and after that getting x.x doesn't see the property any more either). But in the first case, the Qt case, there's a different metaclass, and it IS a subclass of type (so it's not really correct to say the class "isn't new-style"!), and things therefore DO work correctly.

OTHER TIPS

Properties of the Python sort work, in my experience, just fine on PyQt4 objects. I don't know if they are explicitly supported by PyQt4 or not or if there are some hidden gotchas, but I've never seen them misbehave. Here's an example using PyQt 4.4 and Python 2.5:

from PyQt4.QtCore import QObject

class X( QObject ):

    def __init__(self):
        self.__x = 10

    def get_x(self):
        return self.__x

    def set_x(self, x):
        self.__x = x

    x = property(get_x, set_x)

x = X()
print x.x # Should be 10
x.x = 30
print x.x # Should be 30

pyqtProperty is to allow using Qt's property system which is not the same as Python's. Qt properties are introspectable from within Qt's C++ classes (which raw Python properties are not), and are used by Qt for such things as their Qt Designer form editor, and Qt Creator IDE. They allow a lot of the sort of introspection of run-time state that you have in Python and miss in C++. In general Qt provides some of the features of dynamic languages to C++, and this is not the only area where PyQt provides More Than One Way To Do the same thing (consider also strings, dictionaries, file I/O and so on). With most of those choices the main advice I have is just to pick one side or the other and stick with it, just to avoid the possibility of some unpleasant incompatibility. I tend to prefer the Python version over the Qt version because Python is more core to my work than Qt is. If you were going to consider porting anything from PyQt back to C++ Qt, than you might prefer the Qt version of a feature over the Python one.

At least in PyQt4.5, Qt classes certainly ARE new style objects, as seen from their method resolution order:

from PyQt4 import QtGui
print QtGui.QWidget.__mro__
(<class 'PyQt4.QtGui.QWidget'>, <class 'PyQt4.QtCore.QObject'>, <type 'sip.wrapper'>, <class 'PyQt4.QtGui.QPaintDevice'>, <type 'sip.simplewrapper'>, <type 'object'>)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top