copyreg模块在这里使用得当吗?

时间:2013-06-11 14:30:22

标签: python windows types pickle

有谁能告诉我为什么我的代码和函数序列化处理程序在下面不起作用? copyreg模块对我来说是相当陌生的,不清楚下面的代码是否写得正确。

>>> import pickle, copyreg, types, marshal
>>> def average(*args):
    return sum(args) / len(args)

>>> average_dump = pickle.dumps(average)
>>> del average
>>> average = pickle.loads(average_dump)
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    average = pickle.loads(average_dump)
AttributeError: 'module' object has no attribute 'average'
>>> 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)

>>> average_dump
b'\x80\x03c__main__\naverage\nq\x00.'
>>> pickle.dumps(average)
b'\x80\x03c__main__\naverage\nq\x00.'
>>> del average; average = pickle.loads(average_dump)
Traceback (most recent call last):
  File "<pyshell#39>", line 1, in <module>
    del average; average = pickle.loads(average_dump)
AttributeError: 'module' object has no attribute 'average'

我的期望是,如果注册的函数正常工作,那么代码和函数对象都将被序列化。如果按预期工作,也可以使用unpickling函数。


修改:按照this answer中的建议对Pickler进行子类化。似乎也没有帮助。该示例中的函数仍然按名称而不是copyreg模块中的处理程序进行序列化。

>>> import pickle, copyreg, types, marshal
>>> 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)
>>> class MyPickler(pickle.Pickler):
    def __init__(self, *args):
        super().__init__(*args)
        self.dispatch_table = copyreg.dispatch_table


>>> def average(*args):
    return sum(args) / len(args)

>>> x = io.BytesIO(); y = MyPickler(x)
>>> y.dump(average)
>>> x.getvalue()
b'\x80\x03c__main__\naverage\nq\x00.'

2 个答案:

答案 0 :(得分:0)

如果要序列化功能,请运行以下命令:

pip install dill

完成后,您可以import dill并使用它代替pickle模块。

如果您运行的是Python 3,并且希望轻松访问pip,则将一个批处理文件放入名为pip.bat的Windows目录中,并在其中放入以下行(假设您有一个干扰SSL):

py -3 -m pip %* --trusted-host pypi.org --trusted-host files.pythonhosted.org

答案 1 :(得分:-1)

功能不能按值腌制:

  

请注意,函数(内置和用户定义)由“完全限定”的名称引用而非值引用。这意味着只有函数名称被腌制,以及定义函数的模块的名称。函数的代码或其任何函数属性都不被pickle。因此定义模块必须是在unpickling环境中可导入,模块必须包含命名对象,否则将引发异常。

http://docs.python.org/2/library/pickle.html#what-can-be-pickled-and-unpickled