PyQt QVariant with dictionary

1.8k Views Asked by At

If you execute this code in python:

from PyQt4 import uic, QtCore, QtGui
qvdict = QtCore.QVariant(dict(name='a'))
print qvdict.toPyObject()
qvtuple = QtCore.QVariant(('name','a'))
print qvtuple.toPyObject())

The result is:

{PyQt4.QtCore.QString(u'name'): PyQt4.QtCore.QString(u'a')}
('name', 'a')

As you can see keys and string values in qvdict are converted to QString but not for the qvtuble.

Is there a way to preserve the dictionary exactly as it was when initialysing the QVariant object when using toPyObject method?

I know I can do the conversion my-self by rebuilding the dictionary and converting each keys and string values, but shouldn't their be a way so Qt give me back the exactly same object?

If anybody knows why Qt is doing this conversion, I'd like understand why it's like this.

1

There are 1 best solutions below

0
On BEST ANSWER

PyQt will try to convert to the corresponding C++ type if it can.

For a dict, this means a QMap - but only if all the keys are strings. Otherwise, it just wraps a reference to the original dict (i.e. there is no implicit copying).

For a list, the conversion is to a QList, but it isn't necessary that all the contained elements are also convertible.

For a tuple, there is no corresponding C++ type, and so no conversion is attempted (the QVariant will therefore just contain a wrapped reference).

This should immediately suggest a workaround to ensure that any python object is preserved when converting to and from a QVariant: simply wrap it in a tuple. However, a better long-term solution might be to avoid the use of QString and QVariant altogether. If you're using Python 2, this can be done using the sip module to switch to the v2 API:

import sip
sip.setapi('QString', 2)
sip.setapi('QVariant', 2)

from PyQt4 import QtCore, QtGui

Alternatively, you can just use Python 3, where the v2 API is the default.