TypeError用于Python中自定义对象数组的pickle

时间:2014-05-13 14:22:45

标签: python pickle kivy stderr

我有以下方法:

def save(self):
    vertices = self.mindmap.get_vertices()
    edges = self.mindmap.get_edges()

    output = open('mindmap.pkl', 'wb')

    pickle.dump(edges, output)
    pickle.dump(vertices, output)

    output.close()

当我调用此方法时,我收到以下错误:

Traceback (most recent call last):
  File "main.py", line 72, in <module>
    MindMapApp().run()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/app.py", line 792, in run
    runTouchApp()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 481, in runTouchApp
    EventLoop.window.mainloop()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/core/window/window_pygame.py", line 381, in mainloop
    self._mainloop()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/core/window/window_pygame.py", line 287, in _mainloop
    EventLoop.idle()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 324, in idle
    self.dispatch_input()
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 309, in dispatch_input
    post_dispatch_input(*pop(0))
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/base.py", line 275, in post_dispatch_input
    wid.dispatch('on_touch_up', me)
  File "_event.pyx", line 316, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4537)
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/uix/behaviors.py", line 110, in on_touch_up
    self.dispatch('on_release')
  File "_event.pyx", line 312, in kivy._event.EventDispatcher.dispatch (kivy/_event.c:4491)
  File "/Applications/Kivy.app/Contents/Resources/kivy/kivy/lang.py", line 1299, in custom_callback
    exec(__kvlang__.co_value, idmap)
  File "./mindmap.kv", line 14, in <module>
    on_release: app.save()
  File "main.py", line 27, in save
    pickle.dump(vertices, output)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1370, in dump
    Pickler(file, protocol).dump(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 600, in save_list
    self._batch_appends(iter(obj))
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 615, in _batch_appends
    save(x)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 306, in save
    rv = reduce(self.proto)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/copy_reg.py", line 71, in _reduce_ex
    state = base(self)
TypeError: __init__() takes exactly 0 positional arguments (1 given)

如果两个数组都为空,我不会收到此错误。生成上述内容时,edges为空,vertices的大小为1。我真的不知道如何解释这个错误,因此不知道如何解决它。

这是我的Vertex__init__

def __init__(self, pos=None, size=None):
    super(Vertex, self).__init__()

    self.pos = pos
    self.size = size

    if self.height < self.MINIMUM_HEIGHT + self.TEXT_OFFSET:
        self.height = self.MINIMUM_HEIGHT + self.TEXT_OFFSET

    if self.width < self.MINIMUM_WIDTH + self.TEXT_OFFSET:
        self.width = self.MINIMUM_WIDTH + self.TEXT_OFFSET

    self.originalSize = self.size
    self.originalWidth = self.size[0]

    self.newIdea = TextInput(
        height = self.MINIMUM_HEIGHT,
        size_hint = (None, None),
        pos_hint = {'center_x':.5, 'center_y':.5},

        background_active = '',
        background_normal = '',

        use_bubble = True,

        foreground_color = (.4, .4, .4, 1),
        cursor_color = (.4, .4, .4, 1))
    self.newIdea.bind(text=self.on_text)

    self.idea = Label(
        height = self.MINIMUM_HEIGHT,
        size_hint = (None, None),
        pos_hint = {'center_x':.5, 'center_y':.5},
        color = (.4, .4, .4,1))

    Logger.info('Vertex: created')

1 个答案:

答案 0 :(得分:4)

事实上,Kivy EventDispatcher对象在这里是错误的; object.__reduce_ex__ method搜索不是自定义类的第一个基类(设置了Py_TPFLAGS_HEAPTYPE标志),以便在该类上调用__init__这个基类的失败,因为它的__init__方法不支持传入单个参数。

解决方法是使用最新的泡菜协议;它使用不同的代码路径:

pickle.dump(edges, output, pickle.HIGHEST_PROTOCOL)
pickle.dump(vertices, output, pickle.HIGHEST_PROTOCOL)

因为最新的pickle协议(2)更有效地支持新式类。

看到Kivy对象层次结构的复杂性,您可能需要自定义酸洗过程。

我会考虑实施__getnewargs__ method例如:

def __getnewargs__(self):
    return (self.pos, self.size)

将确保只是那个数据被腌制,仅此而已。在unpickling上,这两个值然后用于创建 new Vertex对象。请注意,对于要使用的此方法, 使用最新协议!

您还可以实施__getstate__ method;如果您返回字典,则不需要镜像__setstate__方法,但允许您初始化更多属性。

如果两者都未实现,则实例__dict__的内容将被腌制。确保包含的所有内容都可以进行腌制。