4

我正在尝试使用 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,“无法腌制 ListStore 对象”。使用 print 语句,我已经验证了该__getstate__函数在使用 pickle.dump 时运行。我没有从文档中看到任何关于下一步该做什么的提示,所以我有点束手无策。有什么建议么?

4

2 回答 2

1

使用这种方法,您甚至可以使用 json 而不是 pickle 来达到您的目的。

这是一个快速工作示例,向您展示腌制“不可腌制类型”(如gtk.ListStore. 基本上你需要做几件事:

  1. 定义__reduce__哪个返回重建实例所需的函数和参数。
  2. 确定 ListStore 的列类型。该方法self.get_column_type(0)返回一个 Gtype,因此您需要将其映射回相应的 Python 类型。我把它作为练习留了下来——在我的例子中,我使用了一种技巧来从第一行值中获取列类型。
  3. 您的_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]
于 2011-05-11T19:41:29.117 回答
0

当您子类object.__reduce__化对象时,请注意调用__getstate__. 看起来,由于这是 的子类gtk.ListStore,默认实现__reduce__尝试先腌制数据以重建gtk.ListStore对象,然后调用您的__getstate__,但由于gtk.ListStore无法腌制,它拒绝腌制您的类。如果您尝试实施__reduce__and__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. 在那里,您可以通过自己定义自定义类的序列化方式来完全控制序列化过程。另外,默认情况下,它们没有pickle.

于 2011-05-11T19:25:21.477 回答