Crossin的编程教室

标题: 【Python 第65课】pickle [打印本页]

作者: crossin先生    时间: 2014-5-5 18:33
标题: 【Python 第65课】pickle

在之前的课程中,我们有讲到通过文件来保存、中转数据(参见第31、32、33课)。在使用文件存储时,通常需要对数据进行一些处理,按照一定的规范把数据整理成文本,再写入文件中。下次使用时,从文件中读出文本,再按照此规范解析这些数据。

这种将数据转成文本的过程又被称为“序列化”,即将对象状态转换为可保持或传输的格式的过程。对应的,从序列化的格式中解析对象状态的过程被称为“反序列化”。

在之前的课程和示例中,我们都自己手动实现了这个过程。其实 Python 提供了一个标准模块来做这件事,就是 pickle。它可以把任何 Python 对象存储在文件中,再把它原样取出来。

来看一下存储的过程:

import pickle

test_data = ['Save me!', 123.456, True]

f = file('test.data', 'w')
pickle.dump(test_data, f)
f.close()

这样,我们就把 test_data 这个 list 存储在了文件 test.data 中。你可以用文本编辑器打开 test.data 查看里面的内容:

(lp0
S'Save me!'
p1
aF123.456
aI01
a.

这就是经 pickle 序列化后的数据,隐约可以看到之前对象的影子。你可能无法看出这个文件的规律,这没关系,Python 能看懂就可以了。

下面取存储的过程:

import pickle

f = file('test.data')
test_data = pickle.load(f)
f.close()

print test_data

控制台的输出:

['Save me!', 123.456, True]

和存储前的数据是一致的。


如果你想保存多个对象,一种方法是把这些对象先全部放在一个序列中,在对这个序列进行存储:

a = 123
b = "hello"
c = 0.618
data = (a, b, c)
...
pickle.dump(data, f)

另一种方法就是依次保存和提取:

...
pickle.dump(a, f)
pickle.dump(b, f)
pickle.dump(c, f)
...
x = pickle.load(f)
y = pickle.load(f)
z = pickle.load(f)


dump 方法可以增加一个可选的参数,来指定用二进制来存储:

pickle.dump(data, f, True)

而 load 方法会自动检测数据是二进制还是文本格式,无需手动指定。


Python 还提供了另一个模块 cPickle,它的功能及用法和 pickle 模块完全相同,只不过它是用C语言编写的,因此要快得多(比pickle快1000倍)。因此你可以把上述代码中的 pickle 全部替换为 cPickle,从而提高运行速度(尽管在这个小程序中影响微乎其微)。



作者: toddlerya    时间: 2014-7-17 14:04

作者: liu-pengfei    时间: 2014-9-29 21:59
又涨知识了。
作者: daiming    时间: 2015-1-28 12:45

作者: ngtf    时间: 2015-3-1 09:10
那个图片里的是做什么的啊
作者: konggulanyan    时间: 2015-8-28 08:37
感谢楼主分享
作者: 756318887    时间: 2015-10-13 14:06

作者: catherinemic    时间: 2016-2-21 21:26
crossin老师,学习了pickle以后,有个疑问,直接把数据存入txt文件不是也可以吗?因为尝试应用pickle到猜数字小游戏中(第41课:用文件保存游戏),但是仍然不知道该怎么写代码,还是原来直接把分数数据处理后保存到txt文件中更简单些,也可能是我还没有理解pickle的作用吧,您能帮忙解释一下吗?
作者: crossin先生    时间: 2016-2-22 12:56
catherinemic 发表于 2016-2-21 21:26
crossin老师,学习了pickle以后,有个疑问,直接把数据存入txt文件不是也可以吗?因为尝试应用pickle到猜数 ...

你自己做读写的处理是可以。但是复杂的对象,用pickle不是省事吗,又不用自己写处理,只要dump和load就可以了
作者: catherinemic    时间: 2016-2-22 15:48
crossin先生 发表于 2016-2-22 12:56
你自己做读写的处理是可以。但是复杂的对象,用pickle不是省事吗,又不用自己写处理,只要dump和load就可 ...

嗯,好吧,估计以后学到复杂的地方就会用到了~~
作者: exchen    时间: 2016-4-14 18:29
老师运行你代码提示AttributeError: 'module' object has no attribute 'dump'是为啥?
作者: crossin先生    时间: 2016-4-15 11:23
exchen 发表于 2016-4-14 18:29
老师运行你代码提示AttributeError: 'module' object has no attribute 'dump'是为啥?

不知道,看不到代码我猜不出。可能你有地方写错了,也可能你把文件保存成了叫 pickle.py
作者: exchen    时间: 2016-4-15 12:01
crossin先生 发表于 2016-4-15 11:23
不知道,看不到代码我猜不出。可能你有地方写错了,也可能你把文件保存成了叫 pickle.py ...

好像是真的保存成了pickle.py....谢谢老师
作者: blueheart    时间: 2017-8-25 11:32
exchen 发表于 2016-4-15 12:01
好像是真的保存成了pickle.py....谢谢老师

哈哈,我也是把文件保存成了pickle.py所以报错了
作者: blueheart    时间: 2017-8-25 12:02
涨知识了
作者: blueheart    时间: 2017-8-25 12:42
老师运行你代码提示AttributeError: 'module' object has no attribute 'dump'是为啥?
pickle.png
作者: crossin先生    时间: 2017-8-26 13:02
blueheart 发表于 2017-8-25 12:42
老师运行你代码提示AttributeError: 'module' object has no attribute 'dump'是为啥?

文件夹里面是不是有别的文件被你命名成了 pickle.py
作者: crossin先生    时间: 2017-8-26 13:03
blueheart 发表于 2017-8-25 12:42
老师运行你代码提示AttributeError: 'module' object has no attribute 'dump'是为啥?

应该还是一样的命名问题吧,检查下别的文件
作者: 很好吃    时间: 2017-12-16 12:52
crossin先生,我只有这样写才能达到你说的效果
import pickle

test_data = ["Save me!", 123.456, True]

f = open("test.data", "wb")
pickle.dump(test_data, f)
f.close()


import pickle

f = open("test.data","rb")
test_data = pickle.load(f)
f.close()

print (test_data)

如果不用wb和rb就报错
TypeError: write() argument must be str, not bytes
以及TypeError: a bytes-like object is required, not 'str'
请问这是什么原理呢

作者: crossin先生    时间: 2017-12-17 15:33
很好吃 发表于 2017-12-16 12:52
crossin先生,我只有这样写才能达到你说的效果
import pickle

因为 dump 出来的结果不是可读文本,类型不对
你这应该是 py3 的变动
作者: 很好吃    时间: 2017-12-18 09:08
crossin先生 发表于 2017-12-17 15:33
因为 dump 出来的结果不是可读文本,类型不对
你这应该是 py3 的变动

好的,的确是py3,谢谢老师回复
作者: 敦敦敦    时间: 2017-12-21 10:37
请问一下我这边什么地方出问题了
  1. import pickle

  2. test_data = ['Save me!', 123.456, True]

  3. f=open('test.data','wb')
  4. pickle.dump(test_data, f)
  5. f.close()



  6. import pickle

  7. f = open('test.data')
  8. test_data = pickle.load(f)
  9. f.close()

  10. print (test_data)



  11. C:\Users\lenovo\PycharmProjects\untitled\venv\Scripts\python.exe C:/Users/lenovo/AppData/Local/Programs/Python/Python37-32/DLLs/asdfghjkkjhgxcvbnm,
  12. Traceback (most recent call last):
  13.   File "C:/Users/lenovo/AppData/Local/Programs/Python/Python37-32/DLLs/asdfghjkkjhgxcvbnm,", line 14, in <module>
  14.     test_data = pickle.load(f)
  15. UnicodeDecodeError: 'gbk' codec can't decode byte 0x80 in position 0: illegal multibyte sequence

  16. Process finished with exit code 1
复制代码

作者: crossin先生    时间: 2017-12-22 14:19
敦敦敦 发表于 2017-12-21 10:37
请问一下我这边什么地方出问题了

open也要b模式
作者: laotianpeng    时间: 2018-9-15 20:41
老师您好!我用的是python3.7,学到这里总是报错:
Traceback (most recent call last):
  File "C:/Users/Laotianpeng/Desktop/pythonlearn/t1.py", line 4, in <module>
    pickle.dump(test_data,f)
TypeError: write() argument must be str, not bytes
我的代码是:
import pickle
test_data=["Save me !",'123.456',True]
with open('somefile.data','w') as f:
    pickle.dump(test_data,f)
   
作者: crossin先生    时间: 2018-9-16 15:25
laotianpeng 发表于 2018-9-15 20:41
老师您好!我用的是python3.7,学到这里总是报错:
Traceback (most recent call last):
  File "C:/Users/ ...

改成 open('somefile.data','wb')
作者: amengguyi    时间: 2018-10-22 19:19
没有乱码,不好意思!




欢迎光临 Crossin的编程教室 (https://bbs.crossincode.com/) Powered by Discuz! X2.5