序列化和反序列化
我们把变量从内存中变成可存储或传输的过程称之为序列化,序列化之后就可以吧序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,吧变量内容从序列化的对象重新读取到内存里称之为返序列化。
python 提供了pickle模块来实现序列化
把一个对象序列化并写入文件:
import pickle d = dict(name='bob',age=20) pickle.dumps(d)
>>>b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x03\x00\x00\x00bobq\x02X\x03\x00\x00\x00ageq\x03K\x14u.'
pickle.dumps()方法把人与i任意对象序列化成一个bytes,然后,就可以把这个bytes写文件,或者用列一个方法pickle.dump()直接把对象序列化后写入一个file-like object:
f = open('xxx','wb') pickle.dump(d,f) f.close()
当我们要把对象从磁盘督导内存时,可以先把内容读取到一个bytes,然后在用pickle.loads()方法反序列化出对象,也可以直接使用pickle.load()方法直接从一个file-like Object中反序列化出对象
f = open('xxx','rb') pickle.load(f) f.close
若要反序列化多个数据,则需要多次使用pickle.load()方法
反序列化得到的变量和原来的变量时完全不想干的对对象,他们只是呢容相同而已
如果我们用pickle序列化了许多不同类型的对象,当我们想要反序列化摸一个类型时就会显得非常麻烦,但同时我们又不希望使用数据库那么重量级的东西去存储一丢丢数据时,
不放可是尝试一下,python给我们提供的shelve这个模块,shelf也是使用key来访问的,使用起来和字典类似。shelve其实用anybdm去创建DB并且管理持久化对象的。
创建一个新的shelf
直接用shelve.open()方法就可以创建了
import shelve s = shelve.open('db') try: s['keys'] = {'int': 10, 'float':9.5, 'string':'Sample data'} finally: s.close()
如果想要再次访问这个shelf,只需要再次使用shelve.open()方法打开这个文件,然后我们i就可以像使用字典一样来使用这个shelf了。
import shelve s = shelve.open('db') try: info = s['keys'] finally: s.close() print(info)
dbm这个模块有个限制,它不支持多个应用在同一时间对同一个DB进行写操作,所用当我们知道我们的应用只是进行读操作,我们可以让shelve通过只读方式打开DB:
import shelve a = shelve.open('db', flag='r') try: info = a['key'] finally: a.close()
当我们的程序试图去修改一个以只读方式打开的DB时,将会抛出一个异常,异常类型取决于anybdm这个模块在创建DB所选用的DB
写回(Write-back)
由于shelve在默认情况下是不会记录持久化对象的任何修改的,所以我们在shelve.open()时候需要修改默认参数,佛则对象不会保存
def open(filename,flag='c', protocol=None, writeback=False) import shelve s = shelve.open('test_shelf.db') try: print s['key1'] s['key1']['new_value'] = 'this was not here before' finally: s.close() s = shelve.open('test_shelf.db', writeback=True) try: print s['key1'] finally: s.close()
上面这个例子中,由于一开始我们使用了缺省参数shelve.open()了,因此第6行修改的值即使我们s.close()也不会被保存。
所以当我们试图让shelve去自动捕获对象的变化时,我们应该打开shelf的时候将writeback设置为True。当我们将Writeback这个flag设置为True以后,shelf将会将所有从DB中读取的对象放到一个内存缓存中,当我们close()打开的shelf的时候,缓存中的对象会被重新写入DB
import shelve s = shelve.open('db',writeback=True) try: print(s['key1']) s['key1']['new_value'] = 'this was not here before' print(s['key1']) finally: s.close() s = shelve.open('db',writeback=True) try: print(s['key1']) finally: s.close()
writeback方式有优点也有缺点。优点就是减少了我们出错的概率,并且让对象的持久化对用户更加透明了;但这种方式斌不是所有的情况下都需要的,首先,使用writeback以后,shelf在open()时候会增加额外的内存消耗,并且DB在close()的时候会将缓存中的每一个对象都写入到DB,这也会带来额外的等待时间,因为shelve没有办法知道缓存中哪些对象修改了,因此所有的对象都会被写入。
$ python shelve_create.py $ python shelve_writeback.py {'int': 10, 'float': 9.5, 'string': 'Sample data'} {'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'} {'int': 10, 'new_value': 'this was not here before', 'float': 9.5, 'string': 'Sample data'}
不管是pickle还是shelve的问题和所有其他编程语言特有的序列化问题一样,就是他只能用于python。
JSON
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
JSON表示的对象就是标准的JavaScript语言的对象,JSON和Python内置的数据类型对应如下:
JSON类型 | Python类型 |
{} | dict |
[] | list |
"string" | str |
1234.56 | int或float |
true/false | True/False |
null | None |
Python内置的json
模块提供了非常完善的Python对象到JSON格式的转换。我们先看看如何把Python对象变成一个JSON:
import ison d = dict(name='bob',age=12) json.dumps(d) '{"name": "bob", "age": 12}'
dumps()
方法返回一个str
,内容就是标准的JSON。类似的,dump()
方法可以直接把JSON写入一个file-like Object
。
要把JSON反序列化为python对象,用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object读取字符串再反序列化:
json_str = '{"age": 20, "score": 88, "name": "Bob"}' json.loads(json_str) {'age': 20, 'score': 88, 'name': 'Bob'}
由于JSON标准规定JSON编码是UTF-8,所以我们总是能正确地在Python的str
与JSON的字符串之间转换。