我正在尝试使用pickle转储自定义类。 该类是从 gtk 子类化的。ListStore,因为这使得存储特定数据然后使用 gtk 显示它变得更加容易。 这可以复制,如下所示。
import gtk
import pickle
import os
class foo(gtk.ListStore):
pass
if __name__=='__main__':
x = foo(str)
with open(os.path.expandvars('%userprofile%\temp.txt'),'w') as f:
pickle.dump(x,f)
我尝试的解决方案是在我的类中添加一个__getstate__
函数。 据我了解文档,这应该优先于 pickle,以便它不再尝试序列化 ListStore,这是它无法做到的。 但是,当我尝试腌制我的对象时,我仍然从pickle.dump收到相同的错误。 可以按如下方式重现该错误。
import gtk
import pickle
import os
class foo(gtk.ListStore):
def __getstate__(self):
return 'bar'
if __name__=='__main__':
x = foo(str)
with open(os.path.expandvars('%userprofile%\temp.txt'),'w') as f:
pickle.dump(x,f)
在每种情况下,pickle.dump 都会引发一个 TypeError,"can't pickle ListStore 对象"。 使用 print 语句,我已经验证了在使用 pickle.dump 时运行__getstate__
函数。 我没有从文档中看到任何关于下一步该做什么的提示,所以我有点束手无策。 有什么建议吗?
使用此方法,您甚至可以使用 json 而不是 pickle 来实现您的目的。
这是一个快速的工作示例,向您展示腌制"不可挑选的类型"(如gtk.ListStore
)所需的步骤。本质上,您需要做几件事:
- 定义返回重建实例所需的函数和参数的
__reduce__
。 - 确定列表存储的列类型。该方法
self.get_column_type(0)
返回一个 Gtype,因此您需要将其映射回相应的 Python 类型。我将其保留为练习 - 在我的示例中,我使用了一个技巧来从第一行值中获取列类型。 - 您的
_new_foo
函数将需要重新生成实例。
例:
import gtk, os, pickle
def _new_foo(cls, coltypes, rows):
inst = cls.__new__(cls)
inst.__init__(*coltypes)
for row in rows:
inst.append(row)
return inst
class foo(gtk.ListStore):
def __reduce__(self):
rows = [list(row) for row in self]
# hack - to be correct you'll really need to use
# `self.get_column_type` and map it back to Python's
# corresponding type.
coltypes = [type(c) for c in rows[0]]
return _new_foo, (self.__class__, coltypes, rows)
x = foo(str, int)
x.append(['foo', 1])
x.append(['bar', 2])
s = pickle.dumps(x)
y = pickle.loads(s)
print list(y[0])
print list(y[1])
输出:
['foo', 1]
['bar', 2]
当你子类对象时,object.__reduce__
负责调用__getstate__
。看起来,由于这是 gtk.ListStore
的子类,__reduce__
的默认实现首先尝试挑选用于重建gtk.ListStore
对象的数据,然后调用您的__getstate__
,但由于gtk.ListStore
不能被酸洗,它拒绝腌制您的类。如果您尝试实现__reduce__
和__reduce_ex__
而不是__getstate__
,则问题应该会消失。
>>> class Foo(gtk.ListStore):
... def __init__(self, *args):
... super(Foo, self).__init__(*args)
... self._args = args
... def __reduce_ex__(self, proto=None):
... return type(self), self._args, self.__getstate__()
... def __getstate__(self):
... return 'foo'
... def __setstate__(self, state):
... print state
...
>>> x = Foo(str)
>>> pickle.loads(pickle.dumps(x))
foo
<Foo object at 0x18be1e0 (__main__+Foo-v3 at 0x194bd90)>
此外,您可以尝试考虑其他序列化程序,例如 json
。在这里,您可以通过定义如何自己序列化自定义类来完全控制序列化 serialiazaton 过程。另外,默认情况下,它们没有 pickle
的安全问题 .