Вдохновленный предыдущими ответами, я создал функцию, которая принимает некий Qt, который поддерживает QDataSteam и возвращает класс, который наследуется от этого класса и может быть выбран, в следующем примере, который я показываю с QPoygon и QPainterPath:
import pickle
from PyQt5 import QtCore, QtGui
def picklable_reduce(self):
return type(self), (), self.__getstate__()
def picklable_getstate(self):
ba = QtCore.QByteArray()
stream = QtCore.QDataStream(ba, QtCore.QIODevice.WriteOnly)
stream << self
return ba
def picklable_setstate(self, ba):
stream = QtCore.QDataStream(ba, QtCore.QIODevice.ReadOnly)
stream >> self
def create_qt_picklable(t):
return type("Picklable_{}".format(t.__name__), (t,),
{
'__reduce__': picklable_reduce,
'__getstate__': picklable_getstate,
'__setstate__': picklable_setstate
}
)
if __name__ == '__main__':
# QPolygon picklable
Picklable_QPolygon = create_qt_picklable(QtGui.QPolygon)
old_poly = Picklable_QPolygon((QtCore.QPoint(1, 1), QtCore.QPoint(2, 2)))
s = pickle.dumps(old_poly)
new_poly = pickle.loads(s)
assert(old_poly == new_poly)
# QPainterPath picklable
Picklable_QPainterPath = create_qt_picklable(QtGui.QPainterPath)
old_painterpath = Picklable_QPainterPath()
old_painterpath.addRect(20, 20, 60, 60)
old_painterpath.moveTo(0, 0)
old_painterpath.cubicTo(99, 0, 50, 50, 99, 99)
old_painterpath.cubicTo(0, 99, 50, 50, 0, 0);
s = pickle.dumps(old_painterpath)
new_painterpath= pickle.loads(s)
assert(old_painterpath == new_painterpath)
Использование кода операции:
if __name__ == '__main__':
Picklable_QPolygon = create_qt_picklable(QtGui.QPolygon)
file_name = "test_pickle.chip"
poly = Picklable_QPolygon((QtCore.QPoint(1, 1), QtCore.QPoint(2, 2)))
with open(file_name, 'wb') as f:
pickle.dump(poly, f, protocol=2) # , fix_imports=True)
elem = None
with open(file_name, 'rb') as f:
elem = pickle.load(f, encoding='bytes') # , fix_imports=True)
assert(poly == elem)