使用 pickle 转储 gtk.ListStore 的子类

发布于 2024-11-06 04:46:12 字数 1021 浏览 6 评论 0原文

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

I am trying to dump a custom class using pickle. The class was subclassed from gtk.ListStore, since that made it easier to store particular data and then display it using gtk. This can be reproduced as shown here.

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)

The solution that I have tried was to add a __getstate__ function into my class. As far as I understand the documentation, this should take precedence for pickle so that it no longer tries to serialize the ListStore, which it is unable to do. However, I still get an identical error from pickle.dump when I try to pickle my object. The error can be reproduced as follows.

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)

In each case, pickle.dump raises a TypeError, "can't pickle ListStore objects". Using print statements, I have verified that the __getstate__ function is run when using pickle.dump. I don't see any hints as to what to do next from the documentation, and so I'm in a bit of a bind. Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

明月夜 2024-11-13 04:46:12

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

这是一个快速工作示例,向您展示了pickle“不可picklable类型”(如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]

With this method you can even use json instead of pickle for your purpose.

Here is a quick working example to show you the steps you need to employ to pickle "unpicklable types" like gtk.ListStore. Essentially you need to do a few things:

  1. Define __reduce__ which returns a function and arguments needed to reconstruct the instance.
  2. Determine the column types for your ListStore. The method self.get_column_type(0) returns a Gtype, so you will need to map this back to the corresponding Python type. I've left that as an exercise - in my example I've employed a hack to get the column types from the first row of values.
  3. Your _new_foo function will need to rebuild the instance.

Example:

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])

Output:

['foo', 1]
['bar', 2]
别挽留 2024-11-13 04:46:12

当您子类化对象时,object.__reduce__ 负责调用__getstate__。看起来,由于这是 gtk.ListStore 的子类,因此 __reduce__ 的默认实现会尝试 pickle 数据以重建 gtk.ListStore 。 > 首先对象,然后调用您的 __getstate__,但由于 gtk.ListStore 无法进行 pickle,因此它拒绝对您的类进行 pickle。如果您尝试实现 __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。在那里,您可以通过自己定义自定义类的序列化方式来完全控制序列化过程。另外,默认情况下,它们不存在 pickle 的安全问题。

When you subclass object, object.__reduce__ takes care of calling __getstate__. It would seem that since this is a subclass of gtk.ListStore, the default implementation of __reduce__ tries to pickle the data for reconstructing a gtk.ListStore object first, then calls your __getstate__, but since the gtk.ListStore can't be pickled, it refuses to pickle your class. The problem should go away if you try to implement __reduce__ and __reduce_ex__ instead of __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)>

As an addition, you may try to consider other serializers, such as json. There you take full control of the serialiazaton process by defining how custom classes are to be serialized yourself. Plus by default they come without the security issues of pickle.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文