根据文档,这段代码似乎应该腌制一个函数的各种元素并允许它被取消腌制,即使它不存在于当前命名空间中。但是,没有出现任何变化。
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.'
>>>
如您所见,无法解开一个不存在的函数。抛开安全问题不谈,下面的代码有望解决问题并允许对函数进行腌制和取消腌制。
>>> 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.'
>>>
人们会期望,如果代码正常工作,转储函数发出的字节将与以前不同。生成了相同的代码,并且 unpickling 应该是相似的。
>>> 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很有趣,但不会改变函数的原生腌制方式。