0

documentationによると、このコードは、関数のさまざまな要素をピクルし、現在の名前空間に存在しなくてもピクルを解除できるようにする必要があるようです。しかし、変化は見られません。

Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:55:48) [MSC v.1600 32 bit
(Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def average(*args):
...     return sum(args) / len(args)
...
>>> import pickle
>>> ap = pickle.dumps(average)
>>> del average
>>> average = pickle.loads(ap)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'average'
>>> ap
b'\x80\x03c__main__\naverage\nq\x00.'
>>>

ご覧のとおり、存在しない関数を unpickle することは不可能です。セキュリティの問題はさておき、次のコードは問題を修正し、関数を pickle および unpickle できるようにすることが期待されていました。

>>> import marshal, types, copyreg
>>> copyreg.pickle(types.CodeType,
...                lambda code: (marshal.loads, (marshal.dumps(code),)),
...                marshal.loads)
...
>>> up = lambda co, ns, de, cl: types.FunctionType(co, globals(), na, de, cl)
>>> copyreg.pickle(types.FunctionType,
...                lambda function: (up, (function.__code__,
...                                       function.__name__,
...                                       function.__defaults__,
...                                       function.__closure__)),
...                up)
...
>>> def average(*args):
...     return sum(args) / len(args)
...
>>> pickle.dumps(average)
b'\x80\x03c__main__\naverage\nq\x00.'
>>>

コードが適切に機能していれば、関数のダンプによって出力されるバイト数は以前とは異なると予想されます。同じコードが生成され、unpickle も似ているはずです。

>>> del average; average = pickle.loads(_)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'average'
>>>

その理論を確認するのは簡単でした。したがって、関数を別のレイヤーでラップするのではなく、API を使用してネイティブにピクルする方法については、まだ問題が残っています。これは簡単ですが、ずさんな解決策です。

質問:pickle API を使用して、名前だけでなく関数を取得するにはどうすればよいですか? 関数をシリアル化するためのデフォルトの処理をオーバーライドして、参照の代わりに値をキャプチャするにはどうすればよいですか?

参照: 質問 1253528は興味深いものでしたが、関数がネイティブにピクルされる方法は変わりません。

4

0 に答える 0