如何在 pickle 中加载对象?
How to load object in pickle?
我正在尝试加载一个 pickled 字典,但不断出现这样的属性错误
TypeError: a bytes-like object is required, not '_io.BufferedReader'
下面是读写pickle对象的代码。我正在使用 python 2.7.12 在 linux 工作站上倾倒腌制对象。 3.6.4用python把数据传到Mac,这里执行readTrueData()导致上面的错误。
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
f = open(fName,'rb')
# print(f)
# print(type(f))
pC = pickle.loads(f)
return pC
def storeTrueData(atomicConfigs, name):
import quippy
storeDic = {}
#rangeKeys = len(atomicConfigs)
#print(rangeKeys)
qTrain = quippy.AtomsList(atomicConfigs)
print(len(qTrain))
rangeKeys = len(qTrain)
print(rangeKeys)
for i in range(rangeKeys):
#configConsidered = atomicConfigs[i]
trueForce = np.array(qTrain[i].force).T
storeDic[i] = trueForce
f = open("trueData/"+ name + ".pkl", "wb")
pickle.dump(storeDic, f)
f.close()
return None
更新
根据评论中提到的建议,我更改了我的代码如下
a.)pC = pickle.load(f)
b.) pC = pickle.loads(f.read())
在这两种情况下,我都收到以下错误
UnicodeDecodeError: 'ascii' codec can't decode byte 0x87 in position 1: ordinal not in range(128)
如果以这种方式使用 open
,您需要使用 pickle.load(...)
才能阅读。
pC = pickle.loads(f.read())
是你要找的,但你真的应该使用 with
context:
with open(fName, 'rb') as f:
pC = pickle.loads(f.read())
这将确保您的文件正确关闭,尤其是因为您的代码在函数中没有 f.close()
。
您的第一个问题是由参数类型与所选 load*
方法不匹配引起的; loads
需要 bytes
个对象,load
需要文件对象本身。将文件对象传递给 loads
是导致错误的原因。
你的另一个问题是由于 numpy
和 datetime
类型的跨版本兼容性问题; Python 2 个泡菜 str
没有指定编码,但是 Python 3 必须用已知编码(或 'bytes'
解泡它们,以获得原始 bytes
而不是str
)。对于 numpy
和 datetime
类型,you're required to pass encoding='latin-1'
:
Optional keyword arguments are fix_imports, encoding and errors, which are used to control compatibility support for pickle stream generated by Python 2. If fix_imports is true, pickle will try to map the old Python 2 names to the new names used in Python 3. The encoding and errors tell pickle how to decode 8-bit string instances pickled by Python 2; these default to ‘ASCII’ and ‘strict’, respectively. The encoding can be ‘bytes’ to read these 8-bit string instances as bytes objects. Using encoding='latin1' is required for unpickling NumPy arrays and instances of datetime, date and time pickled by Python 2.
无论如何,解决方法是更改:
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
f = open(fName,'rb')
# print(f)
# print(type(f))
pC = pickle.loads(f)
return pC
至:
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
with open(fName, 'rb') as f: # with statement avoids file leak
# Match load with file object, and provide encoding for Py2 str
return pickle.load(f, encoding='latin-1')
出于正确性和性能原因,我还建议在 Python 2 机器上将 pickle.dump(storeDic, f)
更改为 pickle.dump(storeDic, f, protocol=2)
,以便使用更现代的 pickle 协议生成流,一个可以有效地 pickle numpy
数组等的东西。协议 0,默认的 Python 2,不能使用每个字节的最高位(它是 ASCII 兼容的),这意味着原始二进制数据在协议 0 中急剧膨胀,需要大量的位旋转,而协议 2 可以把它生扔掉。协议 2 也是唯一一个有效地 pickle 新样式 类 的 Py2 协议,也是唯一一个可以正确 pickle 某些类型实例的协议(使用 __slots__
/__new__
等的东西)全部.
我还推荐脚本开头:
try:
import cPickle as pickle
except ImportError:
import pickle
与 Python 2 一样,pickle
是在纯 Python 中实现的,既慢又无法使用一些更高效的 pickle 代码。在Python3上,cPickle
没了,但是pickle
自动加速了。在那和使用协议 2 之间,Python 2 机器上的 pickling 应该 运行 much 更快,并且产生 much 更小泡菜。
我正在尝试加载一个 pickled 字典,但不断出现这样的属性错误
TypeError: a bytes-like object is required, not '_io.BufferedReader'
下面是读写pickle对象的代码。我正在使用 python 2.7.12 在 linux 工作站上倾倒腌制对象。 3.6.4用python把数据传到Mac,这里执行readTrueData()导致上面的错误。
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
f = open(fName,'rb')
# print(f)
# print(type(f))
pC = pickle.loads(f)
return pC
def storeTrueData(atomicConfigs, name):
import quippy
storeDic = {}
#rangeKeys = len(atomicConfigs)
#print(rangeKeys)
qTrain = quippy.AtomsList(atomicConfigs)
print(len(qTrain))
rangeKeys = len(qTrain)
print(rangeKeys)
for i in range(rangeKeys):
#configConsidered = atomicConfigs[i]
trueForce = np.array(qTrain[i].force).T
storeDic[i] = trueForce
f = open("trueData/"+ name + ".pkl", "wb")
pickle.dump(storeDic, f)
f.close()
return None
更新
根据评论中提到的建议,我更改了我的代码如下
a.)pC = pickle.load(f)
b.) pC = pickle.loads(f.read())
在这两种情况下,我都收到以下错误
UnicodeDecodeError: 'ascii' codec can't decode byte 0x87 in position 1: ordinal not in range(128)
如果以这种方式使用 open
,您需要使用 pickle.load(...)
才能阅读。
pC = pickle.loads(f.read())
是你要找的,但你真的应该使用 with
context:
with open(fName, 'rb') as f:
pC = pickle.loads(f.read())
这将确保您的文件正确关闭,尤其是因为您的代码在函数中没有 f.close()
。
您的第一个问题是由参数类型与所选 load*
方法不匹配引起的; loads
需要 bytes
个对象,load
需要文件对象本身。将文件对象传递给 loads
是导致错误的原因。
你的另一个问题是由于 numpy
和 datetime
类型的跨版本兼容性问题; Python 2 个泡菜 str
没有指定编码,但是 Python 3 必须用已知编码(或 'bytes'
解泡它们,以获得原始 bytes
而不是str
)。对于 numpy
和 datetime
类型,you're required to pass encoding='latin-1'
:
Optional keyword arguments are fix_imports, encoding and errors, which are used to control compatibility support for pickle stream generated by Python 2. If fix_imports is true, pickle will try to map the old Python 2 names to the new names used in Python 3. The encoding and errors tell pickle how to decode 8-bit string instances pickled by Python 2; these default to ‘ASCII’ and ‘strict’, respectively. The encoding can be ‘bytes’ to read these 8-bit string instances as bytes objects. Using encoding='latin1' is required for unpickling NumPy arrays and instances of datetime, date and time pickled by Python 2.
无论如何,解决方法是更改:
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
f = open(fName,'rb')
# print(f)
# print(type(f))
pC = pickle.loads(f)
return pC
至:
def readTrueData(name):
fName = str('trueData/'+name+'.pkl')
with open(fName, 'rb') as f: # with statement avoids file leak
# Match load with file object, and provide encoding for Py2 str
return pickle.load(f, encoding='latin-1')
出于正确性和性能原因,我还建议在 Python 2 机器上将 pickle.dump(storeDic, f)
更改为 pickle.dump(storeDic, f, protocol=2)
,以便使用更现代的 pickle 协议生成流,一个可以有效地 pickle numpy
数组等的东西。协议 0,默认的 Python 2,不能使用每个字节的最高位(它是 ASCII 兼容的),这意味着原始二进制数据在协议 0 中急剧膨胀,需要大量的位旋转,而协议 2 可以把它生扔掉。协议 2 也是唯一一个有效地 pickle 新样式 类 的 Py2 协议,也是唯一一个可以正确 pickle 某些类型实例的协议(使用 __slots__
/__new__
等的东西)全部.
我还推荐脚本开头:
try:
import cPickle as pickle
except ImportError:
import pickle
与 Python 2 一样,pickle
是在纯 Python 中实现的,既慢又无法使用一些更高效的 pickle 代码。在Python3上,cPickle
没了,但是pickle
自动加速了。在那和使用协议 2 之间,Python 2 机器上的 pickling 应该 运行 much 更快,并且产生 much 更小泡菜。