0

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__呼ばれていますか?ここで混乱しており、どの情報を掲載すればよいか正確にはわかりません。追加の何かが役立つかどうか教えてください。

4

1 に答える 1

3

ドキュメントにあるように、拡張タイプをピクルするための主要なエントリ ポイントは__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: unpickle プロセスは、unpickle プロセスを実行するために関数を見つけることができる必要があります (別のインタープリターインスタンスで発生している可能性があります)。

于 2012-12-07T07:47:00.387 に答える