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



我有以下方法:

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

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

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

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

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

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

我会考虑实现__getnewargs__方法,例如:

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

将确保只是数据被腌制,仅此而已。在取消拾取时,这两个值将用于创建新的Vertex对象。请注意,要使用此方法,必须使用最新协议!

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

如果两者都不实现,则改为对实例__dict__的内容进行pickle。确保中包含的所有东西都可以腌制。

相关内容

  • 没有找到相关文章

最新更新