Pickle 跨平台 __dict__ 属性错误

4 投票
5 回答
1483 浏览
提问于 2025-04-17 16:22

我在使用pickle的时候遇到了一些问题。在OSX和Linux之间一切正常,但在Windows和Linux之间就不行了。所有的pickle字符串都存储在内存中,并通过SSL套接字发送。为了更清楚,我把所有的'\n'替换成了":::",把所有的'\r'替换成了"==="(其实没有'\r')。场景如下:

  • 客户端-Win:运行Python 2.7的小型企业服务器2011
  • 客户端-Lin:运行Python 2.7的Fedora Linux
  • 服务器:运行Python 2.7的Fedora Linux

客户端-Lin向服务器发送一个pickle对象:

ccopy_reg:::_reconstructor:::p0:::(c__main__:::infoCollection:::p1:::c__builtin__:::tuple:::p2:::(VSTRINGA:::p3:::VSTRINGB:::p4:::VSTRINGC:::p5:::tp6:::tp7:::Rp8:::.

客户端-Win向服务器发送一个pickle对象:

ccopy_reg:::_reconstructor:::p0:::(c__main__:::infoCollection:::p1:::c__builtin__:::tuple:::p2:::(VSTRINGA:::p3:::VSTRINGB:::p4:::VSTRINGC:::p5:::tp6:::tp7:::Rp8:::ccollections:::OrderedDict:::p9:::((lp10:::(lp11:::S'string_a':::p12:::ag3:::aa(lp13:::S'string_b':::p14:::ag4:::aa(lp15:::S'string_c':::p16:::ag5:::aatp17:::Rp18:::b.

奇怪的是,Windows客户端发送的pickle里多了些信息,而当Linux客户端尝试加载这个pickle字符串时,我收到了:

Unhandled exception in thread started by <function TestThread at 0x107de60>
Traceback (most recent call last):
  File "./test.py", line 212, in TestThread
    info = pickle.loads(p_string)
  File "/usr/lib64/python2.7/pickle.py", line 1382, in loads
    return Unpickler(file).load()
  File "/usr/lib64/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib64/python2.7/pickle.py", line 1224, in load_build
    d = inst.__dict__
AttributeError: 'infoCollection' object has no attribute '__dict__'

有什么想法吗?

编辑

添加了一些额外的信息请求。

infoCollection类的定义是一样的:

infoCollection = collections.namedtuple('infoCollection', 'string_a, string_b, string_c')

def runtest():
    info = infoCollection('STRINGA', 'STRINGB', 'STRINGC')
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ssl_sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
    ssl_sock.connect((server, serverport))
    ssl_sock.write(pickle.dumps(info))
    ssl_sock.close()

接收函数也差不多,但做了一个

p_string = ssl_sock.read()
info = pickle.loads(p_string)

5 个回答

0

如果你这样做,会发生什么呢?

p_string = ssl_sock.read(nbytes=1.0E6)
info = pickle.loads(p_string)
3

你是不是在用不同的小版本的Python?在2.7.3这个版本里,有个bug导致用来保存和读取命名元组的功能和旧版本不兼容。你可以看看这个链接了解更多:

http://ronrothman.com/public/leftbraned/python-2-7-3-bug-broke-my-namedtuple-unpickling/

2

这是个小技巧,但在不同平台上出现的问题似乎是因为使用了命名元组(namedtuples)和序列化工具(pickle)一起在跨平台环境中造成的。我把命名元组换成了我自己定义的类,结果一切都正常了。

class infoClass(object):
    pass

def infoCollection(string_a, string_b, string_c):
    i = infoClass()
    i.string_a = string_a
    i.string_b = string_b
    i.string_c = string_c
    return i

撰写回答