在计算机应用中,序列化是一个专门的术语。
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。 在序列化期间,对象将其当前状态写入到临时或持久性存储区。 以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
由以上定义,序列化与文本文件存储的主要区别在于其包括“状态信息”。 将变量从内存变成可存储或者是可传输的这个过程称之为序列化。 将变量的内容从序列化的对象中重新读入到内存的过程称之为反序列。
把变量从内存中变成可存储或传输的过程,称之为序列化。Python中叫pickling, 其他语言中也被称为serialization,marshalling,flattening等,都是相同的意思。 序列化之后,就可以把序列化后的内容(序列化后的内容是一个Bytes)写入磁盘,或者通过网络传输到别的机器上。
把变量内容从序列化的对象重新读到内存里,称之为反序列化,即unpickling。 Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python, 并且可能不同版本的Python彼此都不兼容,因此,只能用pickle保存那些不重要的数据,不能成功地反序列化也没关系。
Python语言特定的序列化模块是pickle,但如果要把序列化搞得更通用、更符合Web标准,就可以使用json模块。
json模块的dumps( )
和loads( )
函数是定义得非常好的接口的典范。使用时只需要传入一个必须的参数。
但是,当默认的序列化或反序列机制不满足要求时,又可以传入更多的参数来定制序列化或反序列化的规则,
既做到了接口简单易用,又做到了充分的扩展性和灵活性。
为什么要序列化
内存中的字典、列表、集合以及各种对象,如何保存到一个文件中。
设计一套协议,按照某种规则,把内存中的数据保存到文件中,文件是一个个字节序列。 所以必须把数据额转换为字节序列,输出到文件,这就是序列化,反之,从文件的字节 序列恢复到内存中,就是反序列化。
定义
Serialization序列化,将内存中对象存储下来,把他变成一个个字节。二进制。
deSerialization反序列化,将文件的一个个字节到内存中。 序列化保存到文件就是持久化。 可将数据序列化后持久化,或者网络传输,也可以将文件中或者网络接受到的字节序列反序列化。
Python中用于序列化的两个模块:
- json 用于【字符串】和 【python基本数据类型】 间进行转换。
pickle
用于【python特有的类型】 和 【python基本数据类型】间进行转换。
使用 Pickle
模块
对于Pyhon,在内存中,操作信息需要以Python的某种数据类型(比如说列表,字典)的形式存在。
而要把信息保存到磁盘中,显然不能再让信息以上述提到的Python数据类型的形式存在了,
可能要将信息变成字节的形式。
好,上述这个“变”的过程,就称之为序列化,那么其逆过程显然就被称作反序列化。
具体的实现方式由Python的 pickle
模块给出,这里不赘述。
pickle
模块提供了四个功能:dumps
、dump
、loads
、load
pickle
模块可以将任意的对象序列化成二进制的字符串写入到文件中。
还可以从文件中读取并且转为写入时候类型。
pickle.dumps(obj)
- 功能:将
obj
进行序列化
pickle.dump(obj,f)
- 参数一:被序列化的对象
- 参数二:打开的文件
- 功能:将
obj
序列化并且存入到打开的文件中
pickle.loads(bytes)
- 功能:将二进制的字符串转为对象
pickle.load(f)
- 功能: 将文件中的内容读取并且转为对象
pickle.dumps(obj[, protocol])
将python对象序列化成 pickle
的 bytes
类型数据:
import pickle
d = dict(name='Bob', age=20, score=88)
print(pickle.dumps(d))
b'\x80\x04\x95$\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x03Bob\x94\x8c\x03age\x94K\x14\x8c\x05score\x94KXu.'
序列化写入文件。
pickle.dump(obj, file,[protocol])
序列化对象,并将结果数据流写入到文件对象中。
参数 protocol
是序列化模式,默认值为0,表示以文本的形式序列化。
protocol
的值还可以是1或2,表示以二进制的形式序列化。
f = open('xx_openfile3.txt','wb')
print(pickle.dump(d, f) )
f.close()
None
反序列化读取文件。
pickle.load(file)
将file
中的对象序列化读出。
f = open('xx_openfile3.txt','rb')
d = pickle.load(f)
f.close()
print(d)
{'name': 'Bob', 'age': 20, 'score': 88}
pickle.loads(string)
从 string
中读出序列化前的 obj
对象。
ls = ['12', '34', '56']
str = pickle.dumps(ls)
mes = pickle.loads(str)
mes
['12', '34', '56']
使用 JSON 模块
通过(反)序列化能够让信息以想要的形式存在了(其实也是非这样做不可,因为内存只认识变量,而磁盘又只认识字节), Python数据类型如何转化为Java数据类型?),Json就是解决这个问题的方法! 它提供了一种过渡类型,让Python程序员和Java程序员之间也能交换信息。
json模块提供的方法,可以直接将python基本数据类型序列化为json字符串。 Json模块提供了四个功能:dumps、dump、loads、load 。 也可以将json字符串转为python的基本数据类型。
json.dumps(obj,default)
obj
:被序列化的对象default
:函数,将对象转为字典的函数- 功能:将对象序列化为json字符串
json.dump(obj,f,default)
obj
:被序列化的对象f
:打开的文件对象default
:函数,将对象转为字典的函数- 功能:将对象序列化为json字符串并且写入到打开的文件对象中
json.loads(s,object_hook)
- 参数一:字符串
- 参数二:将字典转为对象的函数
- 功能: 将字符串反序列化成对象
json.load(f,object_hook)
- 参数一:打开的文件对象
- 参数二:将字典转为对象的函数
- 功能: 将打开的文件对象的内容读取并且反序列化成对象
序列化并对 key
进行排序及格式化输出。
Json.dumps()
可以格式化大部分的基本数据类型为字符串 。
json中不存在元组。序列化元组之后元组变列表:
import json
print(json.dumps({'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}, sort_keys=True, indent=4))
{ "a": "str", "b": 11.1, "c": true, "d": null, "e": 10, "f": [ 1, 2, 3 ], "g": [ 4, 5, 6 ] }
Json.loads()
用于将字典,列表形式的字符串转换成相应的字典,列表。
json.loads('{"a": "str", "c": true, "b": 11.1, "e": 10, "d": null, "g": [4, 5, 6], "f": [1, 2, 3]}')
{'a': 'str', 'c': True, 'b': 11.1, 'e': 10, 'd': None, 'g': [4, 5, 6], 'f': [1, 2, 3]}
Json.dump()
将基本数据类型,列表,字典,转换成字符串。
v = {'k1':'yh','k2':'小马过河'}
f = open('xiaoma.txt',mode='w',encoding='utf-8') #文件不存在就会生成
val = json.dump(v,f)
val
f.close()
Json.load()
将json格式的字符串转换成Python的数据类型。
v2 = '["mcw",123]'
print(type(v2))
v3 = json.loads(v2)
print(v3,type(v3))
<class 'str'> ['mcw', 123] <class 'list'>
使用 shelve
模块
使用json
或者 pickle
持久化数据,能 dump
多次,但 load
的话只能取到最新的 dump
,
因为先前的数据已经被后面 dump
的数据覆盖掉了。如果想要实现 dump
多次不被覆盖,
可以使用 shelve
模块。
shelve
是一个简单的数据存储方案,类似 key-value
数据库,可以很方便的保存Python对象,
其内部是通过pickle
协议来实现数据序列化。shelve
只有一个open()
函数,
这个函数用于打开指定的文件(一个持久的字典),然后返回一个shelf
对象。
shelf
是一种持久的、类似字典的对象。它与“dbm”的不同之处在于,
其values
值可以是任意基本Python对象pickle
模块可以处理的任何数据。
这包括大多数类实例、递归数据类型和包含很多共享子对象的对象。
keys
还是普通的字符串。
open(filename, flag='c', protocol=None, writeback=False)
flag
参数表示打开数据存储文件的格式,可取值与 dbm.open()
函数一致:
'r'
以只读模式打开一个已经存在的数据存储文件'w'
以读写模式打开一个已经存在的数据存储文件'c'
以读写模式打开一个数据存储文件,如果不存在则创建'n'
总是创建一个新的、空数据存储文件,并以读写模式打开
protocol
参数表示序列化数据所使用的协议版本,默认是pickle v3
;
writeback
参数表示是否开启回写功能。
可以把 shelf
对象当 dict
来使用--存储、更改、查询某个 key
对应的数据,
当操作完成之后,调用 shelf
对象的close()
函数即可。当然,
也可以使用上下文管理器( with
语句),避免每次都要手动调用close()
方法。
内置数据类型操作: 保存数据。
import shelve
with shelve.open('student') as db:
db['name'] = 'Tom'
db['age'] = 19
db['hobby'] = ['篮球', '看电影', '弹吉他']
db['other_info'] = {'sno': 1, 'addr': 'xxxx'}
读取数据。
with shelve.open('student') as db:
for key,value in db.items():
print(key, ': ', value)
name : Tom age : 19 hobby : ['篮球', '看电影', '弹吉他'] other_info : {'sno': 1, 'addr': 'xxxx'}
自定义数据类型操作: 自定义class
。
class Student(object):
def __init__(self, name, age, sno):
self.name = name
self.age = age
self.sno = sno
def __repr__(self):
return 'Student [name: %s, age: %d, sno: %d]' % (self.name, self.age, self.sno)
保存数据。
tom = Student('Tom', 19, 1)
jerry = Student('Jerry', 17, 2)
with shelve.open("stu.db") as db:
db['Tom'] = tom
db['Jerry'] = jerry
读取数据。
with shelve.open("stu.db") as db:
print(db['Tom'])
print(db['Jerry'])
Student [name: Tom, age: 19, sno: 1] Student [name: Jerry, age: 17, sno: 2]
用 shelve
模块保存变量
利用 shelve
模块,可以将Python程序中的变量保存到二进制的 shelf
文件中。
这样,程序就可以从硬盘中恢复变量的数据。
shelve
模块在程序中添加“保存”和“打开”功能。
例如,如果运行一个程序,并输入了一些配置设置,就可以将这些设置保存到一个 shelf
文件,
让程序下一次运行时加载。
Shelve
也是Python标准库中的一个模块,它是基于 Pickle
的一种简单数据库实现。
Shelve
可以将Python对象存储到文件中,然后通过键值对的形式来访问和修改对象。
与 Pickle
相比,Shelve
提供了更方便的方式来管理对象的持久化存储。
在交互式环境中输入以下代码:
sfile = '/tmp/sdata'
import shelve
shelfFile = shelve.open(sfile )
cats = ['Zophie','Pooka','Simon']
shelfFile['cats'] = cats
shelfFile.close()
要利用 shelve
模块读写数据,首先要导入它。
调用函数 shelve.open()
并传入一个文件名,然后将返回的值保存在一个变量中。
可以对这个变量的 shelf
值进行修改,就像它是一个字典一样。
当完成时,在这个值上调用 close()
。
这里的 shelf
值保存在 shelfFile
中。
创建了一个列表 cats
,并写下 shelfFile['cats'] = cats
,将该列表保存在 shelfFile
中,
作为键 'cats'
关联的值(就像在字典中一样),
在 shelffile
上调用 close()
。
在 Windows 上运行前面的代码,会看到在当前工作目录下有3个新文件:mydata.bak
、 mydata.dat
和 mydata.dir
。
在OS X上,只会创建一个 mydata.db
文件。
这些二进制文件包含了存储在 shelf
中的数据。
这些二进制文件的格式并不重要,只需要知道 shelve
模块做了什么,而不必知道它是怎么做的。
该模块不用操心如何将程序的数据保存到文件中。
程序稍后可以使用 shelve
模块,重新打开这些文件并取出数据。
shelf
值不必用读模式或写模式打开,因为它们在打开后,既能读又能写。
在交互式环境中输入以下代码:
shelfFile = shelve.open(sfile )
type(shelfFile)
shelve.DbfilenameShelf
shelfFile['cats']
['Zophie', 'Pooka', 'Simon']
shelfFile.close()
这里打开了 shelf
文件,检查数据是否正确存储。
输入 shelfFile['cats']
将返回前面保存的同一个列表,
所以就知道该列表得到了正确存储,然后调用 close()
。
就像字典一样,shelf
值有 keys()
和 values()
方法,返回 shelf
中键和值的类似列表的值。
因为这些方法返回类似列表的值,而不是真正的列表,所以应该将它们传递给 list()
函数,
取得列表的形式。在交互式环境中输入以下代码:
shelfFile = shelve.open(sfile )
list(shelfFile.keys())
['cats']
list(shelfFile.values())
[['Zophie', 'Pooka', 'Simon']]
shelfFile.close()
创建文件时,如果需要在 Notepad
或 TextEdit
这样的文本编辑器中读取它们,纯文本就非常有用。
但是,如果想要保存 Python程序中的数据,那就使用 shelve
模块。
import pprint
cats = [{'name': 'Zophie', 'desc': 'chubby'}, {'name':'Pooka', 'desc': 'fluffy'}]
pprint.pformat(cats)
"[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]"
fileObj = open('myCats.py','w')
fileObj.write('cats = ' + pprint.pformat(cats) + '\n')
83
fileObj.close()
这里导入了 pprint
,以便能使用 pprint.pformat()
。
有一个字典的列表,保存在变量 cats
中。
为了让 cats
中的列表在关闭交互式环境后仍然可用,利用 pprint.pformat()
,将它返回为一个字符串。
当有了 cats
中数据的字符串形式,就很容易将该字符串写入一个文件,将它命名为 myCats.py
。
import
语句导入的模块本身就是Python脚本。
如果来自 pprint.pformat()
的字符串保存为一个 .py
文件,该文件就是一个可以导入的模块,像其他模块一样。
由于Python脚本本身也是带有 .py
文件扩展名的文本文件,所以 Python 程序甚至可以生成其他Python 程序。
然后可以将这些文件导入到脚本中。
import myCats
myCats.cats
[{'desc': 'chubby', 'name': 'Zophie'}, {'desc': 'fluffy', 'name': 'Pooka'}]
myCats.cats[0]
{'desc': 'chubby', 'name': 'Zophie'}
myCats.cats[0]['name']
'Zophie'
创建一个 .py
文件(而不是利用 shelve
模块保存变量)的好处在于,因为它是一个文本文件,
所以任何人都可以用一个简单的文本编辑器读取和修改该文件的内容。
但是,对于大多数应用,利用 shelve
模块来保存数据,是将变量保存到文件的最佳方式。
只有基本数据类型,诸如整型、浮点型、字符串、列表和字典,可以作为简单文本写入一个文件。例如, File
对象就不能够编码为文本。