序列化模块(json、pickle)

一、定义:

  什么是序列化——将原本的字典、列表等内容转换成一个字符串的过程就叫序列化。

  序列化:字符串、bytes(结果)

  序列:列表、元组、字符串、bytes(有序的数据类型)

  把其他数据类型转化成字符串、bytes序列化的过程。(序列化)

二、序列化的目的:

  1、一某种存储形式使自定义对象持久化。

  2、将对象从一个地方传递到另一个地方。(在网络上传输的只能是bytes、能够存储在文件里的只有bytes和str)

  3、使程序更具维护性。

比如,我们在python代码中计算的一个数据需要给另外一段程序使用,那我们怎么给?
现在我们能想到的方法就是存在文件里,然后另一个python程序再从文件里读出来。
但是我们都知道,对于文件来说是没有字典这个概念的,所以我们只能将数据转换成字典放到文件中。
你一定会问,将字典转换成一个字符串很简单,就是str(dic)就可以办到了,为什么我们还要学习序列化模块呢?
没错序列化的过程就是从dic 变成str(dic)的过程。现在你可以通过str(dic),将一个名为dic的字典转换成一个字符串,
但是你要怎么把一个字符串转换成字典呢?
聪明的你肯定想到了eval(),如果我们将一个字符串类型的字典str_dic传给eval,就会得到一个返回的字典类型了。
eval()函数十分强大,但是eval是做什么的?e官方demo解释为:将字符串str当成有效的表达式来求值并返回计算结果。
BUT!强大的函数有代价。安全性是其最大的缺点。
想象一下,如果我们从文件中读出的不是一个数据结构,而是一句"删除文件"类似的破坏性语句,那么后果实在不堪设设想。
而使用eval就要担这个风险。
所以,我们并不推荐用eval方法来进行反序列化操作(将str转换成python中的数据结构)

@谨慎使用eval方法。

 

三、json模块:json模块提供了四个功能:dumps、dump、loads、load

  1、dumps和loads:

import json
dic = {'k1':'v1','k2':'v2','k3':'v3'}
str_dic = json.dumps(dic)  #序列化,将一个字典转化成一个字符串。
print(type(str_dic),str_dic)
# 结果:<class 'str'> {"k1": "v1", "k2": "v2", "k3": "v3"}
#注意:json转换完成后的字符串类型的字典中字符串是由""表示的

dic2 = json.loads(str_dic)  #反序列化,将一个字符串格式的字典转换成一个字典
print(type(dic2),dic2)  
# 结果:<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}
# 注意:要用json.loads方法处理字符串类型的字典必须由""表示



list_dic = [1,["a","b","c"],3,{'k1': 'v1', 'k2': 'v2'}]
str_dic = json.dumps(list_dic)   #也可以处理嵌套的数据类型
print(type(str_dic),str_dic)
# 结果:<class 'str'> [1, ["a", "b", "c"], 3, {"k1": "v1", "k2": "v2"}]

list_dic2 = json.loads(str_dic)
print(type(list_dic2),list_dic)
# 结果:<class 'list'> [1, ['a', 'b', 'c'], 3, {'k1': 'v1', 'k2': 'v2'}]

  2、dump和load:

import json
f = open('json_file',mode='w',encoding="utf-8")
dic = {'k1':'v1','k2':'v2','k3':'v3'}
json.dump(dic,f)   #dump方法接收一个文件句柄,直接将字典转换成json字符串写入文件中
f.flush()
f.close()

f = open('json_file')
dic2 = json.load(f)   #load方法接收一个文件句柄,直接将文件中的json字符串换成数据结构返回
f.close()
print(type(dic2),dic2)
# 结果:<class 'dict'> {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'}

   @ensure_ascii关键字参数

import json
f = open('file',mode='w',encoding='utf-8')
json.dump({"国籍":"中国"},f)
ret = json.dumps({"国籍":"中国"})
f.write(ret+"\n")
json.dump({"国籍":"美国"},f,ensure_ascii=False)
ret = json.dumps({"国籍":"美国"},ensure_ascii=False)
f.write(ret+"\n")
f.flush()
f.close()

#结果:
{"\u56fd\u7c4d": "\u4e2d\u56fd"}{"\u56fd\u7c4d": "\u4e2d\u56fd"}
{"国籍": "美国"}{"国籍": "美国"}

  @json的格式化输出

import json
data = {"naem":["张无忌","无忌"],"sex":"","age":"24"}
json_dic = json.dumps(data,sort_keys=True,indent=4,separators=(",",":"),ensure_ascii=False)
print(json_dic)
# 结果:
{
    "age":"24",
    "naem":[
        "张无忌",
        "无忌"
    ],
    "sex":""
}



@格式化输出的参数详情:
Serialize obj to a JSON formatted str.(字符串表示的json对象)
Skipkeys:默认值是False,如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None),设置为False时,就会报TypeError的错误。此时设置成True,则会跳过这类key
ensure_ascii:,当它为True的时候,所有非ASCII码字符显示为\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示。)
If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse).
If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity).
indent:应该是一个非负的整型,如果是0就是顶格分行显示,如果为空就是一行最紧凑显示,否则会换行且按照indent的数值显示前面的空白分行显示,这样打印出来的json数据也叫pretty-printed json
separators:分隔符,实际上是(item_separator, dict_separator)的一个元组,默认的就是(‘,’,’:’);这表示dictionary内keys之间用“,”隔开,而KEY和value之间用“:”隔开。
default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.
sort_keys:将数据根据keys的值进行排序。
To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.


 3、json的各种问题

import json
# 问题1
dic = {1:"v1",2:"v2"}
ret = json.dumps(dic)  #序列化
print(dic,type(dic))
print(ret,type(ret))
# 结果:
# {1: 'v1', 2: 'v2'} <class 'dict'>
# {"1": "v1", "2": "v2"} <class 'str'>
res = json.loads(ret)  #反序列化
print(res,type(res))
# 结果:{'1': 'v1', '2': 'v2'} <class 'dict'>   现在的key值变成字符串了。

# 问题2
dic = {1:[1,2,3],2:(4,5,"abc")}
ret = json.dumps(dic)  #序列化
print(dic,type(dic))
print(ret,type(ret))
# 结果:
# {1: [1, 2, 3], 2: (4, 5, 'abc')} <class 'dict'>
# {"1": [1, 2, 3], "2": [4, 5, "abc"]} <class 'str'>
res = json.loads(ret)  #反序列化
print(res,type(res))
# 结果:{'1': [1, 2, 3], '2': [4, 5, 'abc']} <class 'dict'>

# 问题3
s = {1,2,"abc"}
json.dumps(s)
# 结果:报错(TypeError: Object of type 'set' is not JSON serializable)

# 问题4
s = {(1,2,3):"abc"}
json.dumps(s)
# 结果:报错(TypeError: keys must be a string)

# 问题5:
dic = {"k1":"v1","k2":"v2"}
with open("json_file",mode='a',encoding='utf-8') as f:
    json.dump(dic,f)
    json.dump(dic,f)
    json.dump(dic,f)

with open('json_file',mode='r',encoding='utf-8') as f:
    dic = json.load(f)
print(dic.keys())
# 结果:报错(json.decoder.JSONDecodeError: Extra data: line 1 column 25 (char 24))
# 不支持连续的存 取



@json操作文件
import json
# 向文件中记录字典
dic = {"key1":"value1","key2":"value2"}
ret = json.dumps(dic)  #序列化
with open("json_file",mode='a',encoding='utf-8') as f:
    f.write(ret)

# 从文件中读取字典
with open("json_file",mode='r',encoding='utf-8') as f:
    str_dic = f.read()
dic = json.loads(str_dic)
print(dic.keys())
# 结果:dict_keys(['key1', 'key2'])


#dump和load直接操作文件中的字典
dic = {"key1":"value1","key2":"value2"}
with open("json_file",mode='a',encoding='utf-8') as f:
    json.dump(dic,f)

with open("json_file",mode='r',encoding='utf-8') as f:
    dic = json.load(f)
print(dic.keys())
# 结果:dict_keys(['key1', 'key2'])


#把一个一个的字典放到文件中,在一个一个取出来
import json
dic = {"key1":"value1","key2":"value2"}
with open('json_file',mode='w',encoding='utf-8') as f:
str_dic = json.dumps(dic)
f.write(str_dic+"\n")
str_dic = json.dumps(dic)
f.write(str_dic + "\n")
str_dic = json.dumps(dic)
f.write(str_dic + "\n")

with open('json_file',mode='r',encoding='utf-8') as f:
for el in f:
dic = json.loads(el.strip())
print(dic.keys())
# 结果:
# dict_keys(['key1', 'key2'])
# dict_keys(['key1', 'key2'])
# dict_keys(['key1', 'key2'])


@总结:
1、json在所有语言之间都通用,json序列化的数据在python上序列化了那在Java中也可以反序列化。
  能够处理的数据类型是非常有限的:字符串、列表、字典、数字 (字典中的key只能是字符串)

2、dumps和loads
  在内存中做数据转换:
    dumps 数据类型转成字符串-->序列化
    loads 字符串转成数据类型-->反序列化
  dump和load
  直接将数据类型写入文件,直接从文件中读出数据类型
    dump 数据类型写入文件-->序列化
    load 文件读出数据类型-->反序列化

 四、pickle模块:在python中几乎支持所有的数据类型,只能在python中使用

  1、dumps的结果只能是字节

import pickle
dic = {(1,2,3):{'a','b'},1:'abc'}
ret = pickle.dumps(dic)
print(ret)    #dumps的结果只能是字节
# 结果:
# b'\x80\x03}q\x00(K\x01K\x02K\x03\x87q\x01cbuiltins\nset\nq\x02]
# q\x03(X\x01\x00\x00\x00aq\x04X\x01\x00\x00\x00bq\x05e\x85q\x06Rq\x07K\x01X\x03\x00\x00\x00abcq\x08u.'

res = pickle.loads(ret)
print(res)
# 结果:{(1, 2, 3): {'a', 'b'}, 1: 'abc'}

  2、在和文件操作的时候,需要用rb、wb的模式打开文件

import pickle
dic = {(1,2,3):{'a','b'},1:'abc'}
with open('pickle_file',mode='wb') as f:
    pickle.dump(dic,f)

with open('pickle_file',mode='rb') as f:
    ret = pickle.load(f)
    print(ret,type(ret))
# 结果:{(1, 2, 3): {'b', 'a'}, 1: 'abc'} <class 'dict'>

  3、可以多次dump和多次load

import pickle
dic1 = {(1,2,3):{'a','b'},1:'abc'}
dic2 = {(1,2,3):{'a','b'},2:'abc'}
dic3 = {(1,2,3):{'a','b'},3:'abc'}
dic4 = {(1,2,3):{'a','b'},4:'abc'}
with open('pick_file',mode='wb') as f:
    pickle.dump(dic1,f)
    pickle.dump(dic2,f)
    pickle.dump(dic3,f)
    pickle.dump(dic4,f)

with open('pick_file',mode='rb') as f:
    ret1 = pickle.load(f)
    print(ret1,type(ret1))
    ret2 = pickle.load(f)
    print(ret2, type(ret2))
    ret3 = pickle.load(f)
    print(ret3, type(ret3))
    ret4 = pickle.load(f)
    print(ret4, type(ret4))
    
# 结果:
# {(1, 2, 3): {'a', 'b'}, 1: 'abc'} <class 'dict'>
# {(1, 2, 3): {'a', 'b'}, 2: 'abc'} <class 'dict'>
# {(1, 2, 3): {'a', 'b'}, 3: 'abc'} <class 'dict'>
# {(1, 2, 3): {'a', 'b'}, 4: 'abc'} <class 'dict'>



@读取时的异常处理

import pickle
with open('pick_file',mode='rb') as f:
while True:
try:
ret = pickle.load(f)
print(ret,type(ret))
except EOFError:
break
# 结果:
# {(1, 2, 3): {'b', 'a'}, 1: 'abc'} <class 'dict'>
# {(1, 2, 3): {'b', 'a'}, 2: 'abc'} <class 'dict'>
# {(1, 2, 3): {'b', 'a'}, 3: 'abc'} <class 'dict'>
# {(1, 2, 3): {'b', 'a'}, 4: 'abc'} <class 'dict'>


  

 

posted @ 2018-08-21 19:44  LW-5208  阅读(240)  评论(0)    收藏  举报