Python 2.7.3 に新しい機能が追加され、動的に作成されたクラスを pickle 化できるようになりました。問題 7689を参照してください。
現在、ユーザーが copy_reg を介して別の pickle メカニズムを要求したとしても、通常の pickle メカニズムを使用して動的に作成されたクラスを pickle することはできません。添付のパッチを使用すると、2 つのコード ブロックを入れ替えるだけで、このカスタマイズが可能になります。
と
copy_reg モジュールは、オブジェクトのカスタム ピクルを処理するために存在します。これは、まさにここで必要なものです。ただし、メタクラスのインスタンスをチェックする#494904のコードは、copy_reg ディスパッチ テーブルを調べる*直前に*これを行います。パッチは pickle.py と cPickle.c でこれらのテストの順序を変更するだけで、メタクラスのインスタンスにカスタム ピックラーを登録できます。
そして2.7.3 変更ログから:
問題 #7689: メタクラスが copy_reg に登録されている場合、動的に作成されたクラスのピクルを許可します。Nicolas M. Thiéry と Craig Citro によるパッチ。
Python 2.6 でこれを回避する唯一の方法は、pickle.py
モジュールをそのバージョンに移植することです。2.7.3 モジュールを 2.6 にバンドルすることもできpickle.py
ます。これは、純粋な Python 実装として動作するはずです。
pickle.Pickler.save
または、メソッドにモンキー パッチを適用します。
from copy_reg import dispatch_table
from types import TypeType, StringType, TupleType
from pickle import Pickler, PicklingError
def pickler_save(self, obj):
# Check for persistent id (defined by a subclass)
pid = self.persistent_id(obj)
if pid:
self.save_pers(pid)
return
# Check the memo
x = self.memo.get(id(obj))
if x:
self.write(self.get(x[0]))
return
# Check the type dispatch table
t = type(obj)
f = self.dispatch.get(t)
if f:
f(self, obj) # Call unbound method with explicit self
return
# Check copy_reg.dispatch_table
reduce = dispatch_table.get(t)
if reduce:
rv = reduce(obj)
else:
# Check for a class with a custom metaclass; treat as regular class
try:
issc = issubclass(t, TypeType)
except TypeError: # t is not a class (old Boost; see SF #502085)
issc = 0
if issc:
self.save_global(obj)
return
# Check for a __reduce_ex__ method, fall back to __reduce__
reduce = getattr(obj, "__reduce_ex__", None)
if reduce:
rv = reduce(self.proto)
else:
reduce = getattr(obj, "__reduce__", None)
if reduce:
rv = reduce()
else:
raise PicklingError("Can't pickle %r object: %r" %
(t.__name__, obj))
# Check for string returned by reduce(), meaning "save as global"
if type(rv) is StringType:
self.save_global(obj, rv)
return
# Assert that reduce() returned a tuple
if type(rv) is not TupleType:
raise PicklingError("%s must return string or tuple" % reduce)
# Assert that it returned an appropriately sized tuple
l = len(rv)
if not (2 <= l <= 5):
raise PicklingError("Tuple returned by %s must have "
"two to five elements" % reduce)
# Save the reduce() output and finally memoize the object
self.save_reduce(obj=obj, *rv)
Pickler.save = pickler_save
上記のモンキー パッチを使用すると、例は Python 2.6.8 で動作します。
>>> pickle.dumps(B)
Hey there
'c__main__\nB\np0\n.'