Использование __getstate__/__setstate__ с pickle завершается неудачно с "ValueError: размер должен быть (int width, int height)"

Я пытаюсь засолить pygame.Surface объект, который не может быть выбран по умолчанию. Что я сделал, так это добавил классические функции выбора в класс и переписал его. Таким образом, он будет работать с остальной частью моего кода.

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__ даже будучи призванным? Я запутался здесь, и я не совсем уверен, какую информацию выложить. Дайте мне знать, если что-нибудь дополнительное поможет.

1 ответ

Как сказано в документации, основной точкой входа для расширения типов является __reduce__ или же __reduce_ex__ методы. Учитывая ошибку, кажется, что по умолчанию __reduce__ реализация не совместима с pygame.Surfaceконструктор.

Таким образом, вам лучше обеспечить __reduce__ метод для Surfaceили внешнюю регистрацию через 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 Функция доступна на верхнем уровне модуля: процесс разборки должен быть в состоянии найти функцию для выполнения процесса расщепления (что может происходить в другом экземпляре интерпретатора).

Другие вопросы по тегам