Python 3.5在不同服务器上进行dill的序列化/反序列化:"KeyError: 'ClassType'"

6 浏览
0 Comments

Python 3.5在不同服务器上进行dill的序列化/反序列化:"KeyError: 'ClassType'"

查看底部的更新内容

--

在这里有一个类似的问题,但从未得到解决:

pickling and unpickling user-defined class

我正在处理一个需要对用户定义的类进行pickle和unpickle的项目,并将它们发送到远程服务器上进行unpickle和调用。我们使用Dill库来实现这一目标,并取得了很大的成功。

不幸的是,我遇到了一个我很难调试的问题。我创建并pickle一个类,如下所示:

import dill, base64
import time, random
class periodicSource(object):
    def __call__(self):
        while True:
            time.sleep(0.1)
            yield random.uniform(20,100)
periodic_src = periodicSource()
a = base64.b64encode(dill.dumps(periodic_src)).decode("ascii")
print(a)

它创建了一个dilled类的ascii表示。

gANjZGlsbC5kaWxsCl9jcmVhdGVfdHlwZQpxAChjZGlsbC5kaWxsCl9sb2FkX3R5cGUKcQFYCQAAAENsYXNzVHlwZXEChXEDUnEEWA4AAABwZXJpb2RpY1NvdXJjZXEFaAFYBgAAAG9iamVjdHEGhXEHUnEIhXEJfXEKKFgIAAAAX19jYWxsX19xC2NkaWxsLmRpbGwKX2NyZWF0ZV9mdW5jdGlvbgpxDChoAVgIAAAAQ29kZVR5cGVxDYVxDlJxDyhLAUsASwFLA0tjQyl4IgB0AABqAQBkAQCDAQABdAIAagMAZAIAZAMAgwIAVgFxAwBXZAAAU3EQKE5HP7mZmZmZmZpLFEtkdHERKFgEAAAAdGltZXESWAUAAABzbGVlcHETWAYAAAByYW5kb21xFFgHAAAAdW5pZm9ybXEVdHEWWAQAAABzZWxmcReFcRhYHwAAADxpcHl0aG9uLWlucHV0LTIwLTdhNGU5MDIwYWM2Yz5xGWgLSwdDBgABAwENAXEaKSl0cRtScRx9cR0oWAYAAAByYW5kb21xHmNkaWxsLmRpbGwKX2ltcG9ydF9tb2R1bGUKcR9oFIVxIFJxIVgEAAAAdGltZXEiaB9YBAAAAHRpbWVxI4VxJFJxJXVoC05OfXEmdHEnUnEoWAoAAABfX21vZHVsZV9fcSlYCAAAAF9fbWFpbl9fcSpYBwAAAF9fZG9jX19xK05YDQAAAF9fc2xvdG5hbWVzX19xLF1xLXV0cS5ScS8pgXEwLg==

当我在另一台服务器上反序列化它时:

a = 'gANjZGlsbC5kaWxsCl9jcmVhdGVfdHlwZQpxAChjZGlsbC5kaWxsCl9sb2FkX3R5cGUKcQFYCQAAAENsYXNzVHlwZXEChXEDUnEEWA4AAABwZXJpb2RpY1NvdXJjZXEFaAFYBgAAAG9iamVjdHEGhXEHUnEIhXEJfXEKKFgIAAAAX19jYWxsX19xC2NkaWxsLmRpbGwKX2NyZWF0ZV9mdW5jdGlvbgpxDChoAVgIAAAAQ29kZVR5cGVxDYVxDlJxDyhLAUsASwFLA0tjQyl4IgB0AABqAQBkAQCDAQABdAIAagMAZAIAZAMAgwIAVgFxAwBXZAAAU3EQKE5HP7mZmZmZmZpLFEtkdHERKFgEAAAAdGltZXESWAUAAABzbGVlcHETWAYAAAByYW5kb21xFFgHAAAAdW5pZm9ybXEVdHEWWAQAAABzZWxmcReFcRhYHwAAADxpcHl0aG9uLWlucHV0LTIwLTdhNGU5MDIwYWM2Yz5xGWgLSwdDBgABAwENAXEaKSl0cRtScRx9cR0oWAYAAAByYW5kb21xHmNkaWxsLmRpbGwKX2ltcG9ydF9tb2R1bGUKcR9oFIVxIFJxIVgEAAAAdGltZXEiaB9YBAAAAHRpbWVxI4VxJFJxJXVoC05OfXEmdHEnUnEoWAoAAABfX21vZHVsZV9fcSlYCAAAAF9fbWFpbl9fcSpYBwAAAF9fZG9jX19xK05YDQAAAF9fc2xvdG5hbWVzX19xLF1xLXV0cS5ScS8pgXEwLg=='
a = dill.loads(base64.b64decode(a.encode()))
print(a)

我得到以下错误:

/home/streamsadmin/anaconda3/bin/python /home/streamsadmin/git/streamsx.topology/test/python/topology/deleteme2.py
Traceback (most recent call last):
 File "/home/streamsadmin/git/streamsx.topology/test/python/topology/deleteme2.py", line 40, in 
   a = dill.loads(base64.b64decode(a.encode()))
 File "/home/streamsadmin/anaconda3/lib/python3.5/site-packages/dill/dill.py", line 277, in loads
   return load(file)
 File "/home/streamsadmin/anaconda3/lib/python3.5/site-packages/dill/dill.py", line 266, in load
   obj = pik.load()
 File "/home/streamsadmin/anaconda3/lib/python3.5/site-packages/dill/dill.py", line 524, in _load_type
   return _reverse_typemap[name]
KeyError: 'ClassType'

如果我在远程系统上使用了不同版本的Python,我会期望得到这个错误,但它们是相同的:

服务器1:

>>> import sys
>>> sys.version
'3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  2 2016, 17:53:06) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]'

服务器2:

>>> import sys
>>> sys.version
'3.5.2 |Anaconda 4.2.0 (64-bit)| (default, Jul  2 2016, 17:53:06) \n[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)]'

此外,Dill的两个版本都是0.2.6。有什么方法可以调试这个问题吗?

编辑:我认为可能是我的环境有问题。我正在使用Python 3.5,但列出了内建类型:

>>> import types
>>> dir(types)
  ['BuiltinFunctionType',
   'BuiltinMethodType',
   'ClassType',
   'CodeType',
   ...
  ]

这是非常奇怪的,因为ClassType应该出现在输出中,因为在Python 3.5中已经删除了ClassType。我正在运行一个同时安装了Python 2.7和Python 3.5的系统。2.7版本是否会以某种方式影响3.5版本的安装?

0
0 Comments

问题出现的原因是使用Python 3.5的dill模块在不同的服务器上进行pickling和unpickling时出现了"KeyError: 'ClassType'"错误。解决方法如下:

首先,确认是否安装了cloudpickle模块,并且它是否导致了问题。可以通过逐步调试来确认。

1. 首先检查builtin types中是否存在classType:

import types

dir(types)

如果存在classType,则应该可以正常工作;如果不存在,则继续下一步。

2. 导入cloudpickle模块,并再次检查builtin types中是否有classType。

3. 执行以下代码:

dill.dill._reverse_typemap['ClassType'] = type

这样应该可以解决问题。

但是,如果仍然出现错误"AttributeError: module 'dill' has no attribute 'dill'",请使用以下代码:

dill._dill._reverse_typemap['ClassType'] = type

因为dill.dill已经移动到dill._dill中。

希望以上方法可以解决你的问题 🙂

0
0 Comments

问题的原因是在Python 3.5中,默认情况下types.ClassType未设置。当导入cloudpickle时,types.ClassType会被定义。在服务器A上,使用dill来序列化对象,并且导入cloudpickle,因此在序列化过程中会引用到ClassType。而服务器B没有导入cloudpickle,在反序列化过程中尝试找到对ClassType的引用,但失败了,导致了错误的发生。

为了解决这个问题,在服务器B上,在导入dill之后,在第一次调用dill.loads之前,我们需要加入如下代码:

dill._dill._reverse_typemap['ClassType'] = type

这样就可以正确定义ClassType,并且使得dill的反序列化能够正常工作。

在我们的系统中,我们无法从环境中移除cloudpickle,所以我们需要使用这种解决方法。非常感谢这个解决方案,只是有一个小的更改:将dill._dill._reverse_typemap['ClassType']改为type

0