【问题标题】:Using __getstate__/__setstate__ with pickle fails with "ValueError: size needs to be (int width, int height)"将 __getstate__/__setstate__ 与 pickle 一起使用会失败,并出现“ValueError: size need to be (int width, int height)”
【发布时间】:2012-11-25 07:28:04
【问题描述】:

我正在尝试腌制pygame.Surface 对象,默认情况下它是不可腌制的。我所做的是将经典的picklability 函数添加到类并覆盖它。这样它将与我的其余代码一起使用。

class TemporarySurface(pygame.Surface):
    def __getstate__(self):
        print '__getstate__ executed'
        return (pygame.image.tostring(self,IMAGE_TO_STRING_FORMAT),self.get_size())

    def __setstate__(self,state):
        print '__setstate__ executed'
        tempsurf = pygame.image.frombuffer(state[0],state[1],IMAGE_TO_STRING_FORMAT)
        pygame.Surface.__init__(self,tempsurf)

pygame.Surface = TemporarySurface

这是我尝试腌制一些递归对象时的回溯示例:

Traceback (most recent call last):
  File "dibujar.py", line 981, in save_project
    pickler.dump((key,value))
  File "/usr/lib/python2.7/pickle.py", line 224, in dump
    self.save(obj)
  File "/usr/lib/python2.7/pickle.py", line 286, in save
    f(self, obj) # Call unbound method with explicit self
  File "/usr/lib/python2.7/pickle.py", line 562, in save_tuple
    save(element)
  File "/usr/lib/python2.7/pickle.py", line 306, in save
    rv = reduce(self.proto)
  File "/usr/lib/python2.7/copy_reg.py", line 71, in _reduce_ex
    state = base(self)
ValueError: size needs to be (int width, int height)

令我困惑的部分是 print 语句没有被执行。 __getstate__ 甚至被调用了吗?我在这里很困惑,我不确定要提供什么信息。如果有任何额外的帮助,请告诉我。

【问题讨论】:

  • 它可能不会被调用,这取决于不同的代码片段如何导入SurfaceSurface 是如何使用的?您是否可以使用您的子类而不是猴子补丁 Surface 本身?
  • 好吧,我正在使用其他人的代码来传递 Surface 对象,所以使用子类对我来说要困难得多。 Surface 正在正常使用,我只在尝试腌制时遇到此错误。
  • 我发现了这个:mail-archive.com/pygame-users@seul.org/msg13420.html 但是,您是否能够检索文件路径或 ID,并保存它而不是实际像素?

标签: python pygame pickle getstate


【解决方案1】:

作为the documentation says,酸洗扩展类型的主要入口点是__reduce____reduce_ex__ 方法。鉴于错误,似乎默认的__reduce__ 实现与pygame.Surface 的构造函数不兼容。

所以你最好为Surface 提供一个__reduce__ 方法,或者通过copy_reg 模块在外部注册一个。我建议后者,因为它不涉及猴子修补。你可能想要这样的东西:

import copy_reg

def pickle_surface(surface):
    return construct_surface, (pygame.image.tostring(surface, IMAGE_TO_STRING_FORMAT), surface.get_size())

def construct_surface(data, size):
    return pygame.image.frombuffer(data, size, IMAGE_TO_STRING_FORMAT)

construct_surface.__safe_for_unpickling__ = True
copy_reg.pickle(pygame.Surface, pickle_surface)

这应该就是你所需要的。确保 construct_surface 函数在模块的顶层可用:解酸过程需要能够定位函数以执行解酸过程(这可能发生在不同的解释器实例中)。

【讨论】:

    猜你喜欢
    • 2015-04-27
    • 1970-01-01
    • 2014-07-05
    • 2012-12-14
    • 2013-11-20
    • 1970-01-01
    • 1970-01-01
    • 2017-10-23
    • 2020-01-14
    相关资源
    最近更新 更多