我有一個用python 2.7創建的pickle文件,我試圖移植到python 3.6。該文件通過pickle.dumps(self.saved_objects, -1)
將pickle py2移植到py3字符串變成字節
保存在py 2.7中,並通過loads(data, encoding="bytes")
(從rb
模式下打開的文件)在python 3.6中加載。如果我嘗試在r
模式下打開,並通過encoding=latin1
到loads
我得到UnicodeDecode錯誤。當我打開它作爲它加載的字節流時,但實際上每個字符串現在是一個字節字符串。每個對象的__dict__
鍵都是b"a_variable_name"
,因此在調用an_object.a_variable_name
時會生成屬性錯誤,因爲__getattr__
傳遞了一個字符串而__dict__
僅包含字節。我覺得我已經嘗試了各種論點和醃製協議的組合。除了強制性地將所有對象的__dict__
鍵轉換爲字符串之外,我不知所措。有任何想法嗎?
** 跳轉到17年4月28日更新更好的例子
-------------------------- -------------------------------------------------- ---------------------------------
** 更新17年4月27日
這個最小的例子說明了我的問題:
從白翎2.7.13
import pickle
class test(object):
def __init__(self):
self.x = u"test ¢" # including a unicode str breaks things
t = test()
dumpstr = pickle.dumps(t)
>>> dumpstr
"ccopy_reg\n_reconstructor\np0\n(c__main__\ntest\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'x'\np6\nVtest \xa2\np7\nsb."
從白翎3.6.1
import pickle
class test(object):
def __init__(self):
self.x = "xyz"
dumpstr = b"ccopy_reg\n_reconstructor\np0\n(c__main__\ntest\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'x'\np6\nVtest \xa2\np7\nsb."
t = pickle.loads(dumpstr, encoding="bytes")
>>> t
<__main__.test object at 0x040E3DF0>
>>> t.x
Traceback (most recent call last):
File "<pyshell#15>", line 1, in <module>
t.x
AttributeError: 'test' object has no attribute 'x'
>>> t.__dict__
{b'x': 'test ¢'}
>>>
-------------------- -------------------------------------------------- ---------------------------------------
更新4/28/17
要重新創建我的問題我張貼的泡菜文件是在蟒蛇2.7.13創建了實際的原始數據鹹菜here
,窗口10使用
with open("raw_data.pkl", "wb") as fileobj:
pickle.dump(library, fileobj, protocol=0)
(協議0所以它的人可讀)
要運行它,你將需要classes.py
# classes.py
class Library(object): pass
class Book(object): pass
class Student(object): pass
class RentalDetails(object): pass
而測試腳本在這裏:
# load_pickle.py
import pickle, sys, itertools, os
raw_pkl = "raw_data.pkl"
is_py3 = sys.version_info.major == 3
read_modes = ["rb"]
encodings = ["bytes", "utf-8", "latin-1"]
fix_imports_choices = [True, False]
files = ["raw_data_%s.pkl" % x for x in range(3)]
def py2_test():
with open(raw_pkl, "rb") as fileobj:
loaded_object = pickle.load(fileobj)
print("library dict: %s" % (loaded_object.__dict__.keys()))
return loaded_object
def py2_dumps():
library = py2_test()
for protcol, path in enumerate(files):
print("dumping library to %s, protocol=%s" % (path, protcol))
with open(path, "wb") as writeobj:
pickle.dump(library, writeobj, protocol=protcol)
def py3_test():
# this test iterates over the different options trying to load
# the data pickled with py2 into a py3 environment
print("starting py3 test")
for (read_mode, encoding, fix_import, path) in itertools.product(read_modes, encodings, fix_imports_choices, files):
py3_load(path, read_mode=read_mode, fix_imports=fix_import, encoding=encoding)
def py3_load(path, read_mode, fix_imports, encoding):
from traceback import print_exc
print("-" * 50)
print("path=%s, read_mode = %s fix_imports = %s, encoding = %s" % (path, read_mode, fix_imports, encoding))
if not os.path.exists(path):
print("start this file with py2 first")
return
try:
with open(path, read_mode) as fileobj:
loaded_object = pickle.load(fileobj, fix_imports=fix_imports, encoding=encoding)
# print the object's __dict__
print("library dict: %s" % (loaded_object.__dict__.keys()))
# consider the test a failure if any member attributes are saved as bytes
test_passed = not any((isinstance(k, bytes) for k in loaded_object.__dict__.keys()))
print("Test %s" % ("Passed!" if test_passed else "Failed"))
except Exception:
print_exc()
print("Test Failed")
input("Press Enter to continue...")
print("-" * 50)
if is_py3:
py3_test()
else:
# py2_test()
py2_dumps()
把所有3在同一目錄並運行c:\python27\python load_pickle.py
第一,這將創建一個爲每個的3個協議1個鹹菜文件。然後用python 3運行相同的命令,並注意它的版本將__dict__
鍵轉換爲字節。我已經工作了大約6個小時,但在我的生活中,我無法弄清楚我是如何再次破壞它的。
你有沒有試過utf-8? – zondo
yeah,ut8,utf16,latin1 ,, cp – user2682863
如果你的泡菜是在一個文件中,爲什麼你使用'loads'而不是'load'? – BrenBarn