Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
目录
Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化
Python第三天 序列 5种数据类型 数值 字符串 列表 元组 字典
Python第四天 流程控制 if else条件判断 for循环 while循环
Python第五天 文件访问 for循环访问文件 while循环访问文件 字符串的startswith函数和split函数
Python第七天 函数 函数参数 函数变量 函数返回值 多类型传值 冗余参数 函数递归调用 匿名函数 内置函数 列表表达式/列表重写
Python第八天 模块 包 全局变量和内置变量__name__ Python path
Python第九天 面向对象 类定义 类的属性 类的方法 内部类 垃圾回收机制 类的继承 装饰器
Python第十天 print >> f,和fd.write()的区别 stdout的buffer 标准输入 标准输出 标准错误 重定向 输出流和输入流
Python第十二天 收集主机信息 正则表达式 无名分组 有名分组
Python第十四天 序列化 pickle模块 cPickle模块 JSON模块 API的两种格式
Python第十五天 datetime模块 time模块 thread模块 threading模块 Queue队列模块 multiprocessing模块 paramiko模块 fabric模块
python中的任何数据类型都可以dump成json格式
https://www.birdpython.com/posts/2/47/
简单序列化
序列化
将对象的状态信息转换为可以存储或传输的形式的过程
不但读写磁盘需要通过文件对象,网络传输数据也需要通过文件对象,因为网络 IO 是指通过文件对象去读写网卡而已,磁盘 IO 是指通过文件对象读写磁盘而已。我们知道文件对象只能处理字符流,如果我们想把非字符类型数据(int,float,bool,list,tuple,dict等等)通过网络发到其他机器或保存到本地文件,那就需要序列化
把变量从内存中变成可存储或传输的过程(也就是变成字符流的过程)
把序列化后的字符流还原成序列化之前的类型数据的过程叫反序列化
最典型场景是
1、很多游戏允许你在退出的时候保存进度,序列化到磁盘,然后你再次启动的时候反序列化回到上次退出的地方
2、序列化为json,在网络上传输
常用的一些序列化
pickle、cPickle 这两个模块用法差不多,cpickle模块,C语言实现,速度是pickle的1000倍,可以先尝试导入cpickle不行再导入pickle
JSON
Shelve
YAML
pickle模块
所有python支持的类型都可以用pickle做序列化
dump(obj, file, protocol=None)
obj:表示序列化的对象,处理循环,递归引用对象,类,函数,类的实例
file:支持write()方法的文件句柄,可以是真实文件,也可以StringIO对象
protocol:序列化协议,0表示ascii协议,ascii码表示,1表示老的二进制协议,2表示新二进制协议,默认为0
pickle的方法
dump保存到磁盘
dumps保存到内存
load 读到磁盘
loads 读到内存
try: import cPickle as pickle except ImportError: import pickle mylist = [1, True, "hello"] seqdata = pickle.dumps(mylist) # 序列化成字符流 print(type(seqdata)) # list 类型数据 序列化成 str 类型 print(seqdata) # 序列化后的字符流 mylistreseq = pickle.loads(seqdata) # 把被序列化的字符流反序列化成 list print(type(mylistreseq)) # list 类型 print(mylistreseq) # 反序列化后的 list
在 Python 3 中,把用 pickle 序列化后的字符流存储到磁盘,必须以 wb 的形式;同样,从磁盘上读取用 pickle 序列化后的字符流用 rb 的形式。
try: import cPickle as pickle except ImportError: import pickle mylist = [1, True, ("hello", None)] f = open("d:/test.txt", "wb") seqdata = pickle.dumps(mylist) # 序列化成字符流 f.write(seqdata) f.close() f = open("d:/test.txt", "rb") seqdata = f.read() f.close() mylistreseq = pickle.loads(seqdata) # 反序列化后的 list print(mylistreseq)
对于我们自定义类型,同样可以使用 pickle 进行序列化。
try: import cPickle as pickle except ImportError: import pickle class myclass(object): def __init__(self): self.data = 250 def func(self): print("ok") myobject = myclass() xx = pickle.dumps(myobject) yy = pickle.loads(xx) print(yy.data) yy.func()
json模块
序列化对象供其他语言读写
JavaScript Object Notation
Json是被设计为跨语言使用的
Json是字符串格式
默认utf-8方式存储
这个模块可以把不同语言的数据类型序列化成统一的数据类型,然后反序列成相应语言的数据类型, 这个模块就是 json 模块,json 就如英文一样,如果中文和日文需要交流,可以先翻译成英文,然后在翻译成自己的语言
javascript,json的key必须用用双引号引住字符串,不能用单引号
json序列化
json.dump() 其他格式数据转为json到磁盘
json.dumps() 其他格式数据转为json到内存
ensure_ascii=True:json只能ascii编码,同样,pickle模块的dump(obj, file, protocol=None),protocol:序列化协议,0表示ascii协议,ascii码表示,默认为0 indent:缩进,让打印出来的json字符串更好看print json.dumps(data, indent=2) encoding='utf-8':默认utf-8编码,utf-8传进来-》ascii default :自定义类json序列化时的处理函数 def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, encoding='utf-8', default=None, sort_keys=False, **kw):
json.load() 从磁盘读json转为其他格式数据
json.loads() 从内存读json转为其他格式数据
encoding=None:load方法可能无法处理中文字符,需要通过encoding参数指定字符编码,如果dumps()方法encoding时候的不是utf-8,需要指定一下编码 object_hook:自定义类反序列化时候的处理函数 def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
数据保存至JSON文件
import json # 序列化 d = {} d['a'] = 'a' d['b'] = 235 d['c'] = ('c1', 'c2') d['d'] = True d['e'] = None with open('/tmp/d.json', mode='w') as fd: json.dump(d, fd)
反序列化
with open('/tmp/d.json') as fd: d1 = json.load(fd)
传递json格式的数据
定义url和方法
def collectjson(req): if req.POST: jsonobj = json.loads(req.body) host = Host() host.hostname = jsonobj['hostname'] host.vendor = jsonobj['vendor'] host.product = jsonobj['product'] host.save()
json 肯定只能支持所有语言都共有的数据类型,比如 int,float,bool 等这些类型,但是并不是所有语言的类型都是一样的,比如 Python 的 set 类型在其它语言中就没有,json 就不会支持对这种类型数据的序列化和反序列化。
import json myset = set([3, 4, 5]) data = json.dumps(myset) # 错误
Python 中的 tuple 类型在其它语言中也没有,但是 tuple 类型和 list 类型很相似,所以 json 会把 tuple 类型数据序列化和反序列化成 Python 的 list 类型数据。 如果是用其它语言进行反序列化我们序列化好的 Python 中的 tuple 类型数据,则会反序列化成其它语言对应的数组类型。
import json mytuple = (1, 2, 4) data = json.dumps(mytuple) dd = json.loads(data) print(type(dd)) # <type 'list'> print(dd) # [1, 2, 4]
Python 中的 dict 类型在其它语言中有类似的类型,比如 C++ 中的 map,Js 中的 object 等等,但是他们的格式有些不同,比如 C++ 中的 map 的键只允许字符串类型等等。我们用 json 序列化和反序列化 Python 的 dict 类型数据,就会只支持键为字符串的 dict,如果键是其它基本数据类型 json 模块会把他转为相应的字符串,如果是 tuple 类型则会报错。
import json seqdata = json.dumps({1: 1, 1.1: 2, "a": 3, None: 4, True: 5}) # 序列化成字符流,并且对不是字符串类型的键做强制转换 dd = json.loads(seqdata) print(dd) # {u'a': 3, u'1': 5, u'null': 4, u'1.1': 2} seqdata = json.dumps({(1,2): 1}) # 虽然字典本身没问题,但是使用 json 序列化会报错
Python 的数据类型对应的 json 数据类型的关系图,当然其它语言的数据类型也对应这同样的 json 数据类型
我们自定义的类对象是否可以用 json 序列化呢,比如我们定义一个 Human 类,然后对 Human 类的对象进行序列化
import json class Human(object): def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex oneman = Human('如花', 18, "女") seqdata = json.dumps(oneman) # 抛出异常,...is not JSON serializable
上面的代码之所以无法把 Human 类对象序列化为 json,是因为默认情况下,json 模块中的 dumps 函数不知道如何将 Human 对象变为一个 json 对象。 dumps 函数的可选参数 default 就是把任意一个对象变成一个可序列为 json 的对象,我们只需要为 Human 类专门写一个转换函数,再把函数传进去即可
import json class Human(object): def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def human2dict(oneman): return { 'name': oneman.name, 'age': oneman.age, 'sex': oneman.sex } oneman = Human('如花', 18, "女") print(json.dumps(oneman, default=human2dict))
因为通常类的对象都有一个 __dict__ 属性,它就是一个 dict,用来存储实例变量。也有少数例外,比如定义了 __slots__ 的 类。同样的道理,如果我们要把 json 反序列化为一个 human 类的对象,json 模块的 loads 函数首先转换出一个 dict 对象,然后,我们传入的 object_hook 函数负责把 dict 转换为 human 类的对象。
import json class Human(object): def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def human2dict(oneman): return { 'name': oneman.name, 'age': oneman.age, 'sex': oneman.sex } def dict2human(d): return Human(d['name'], d['age'], d['sex']) oneman = Human('如花', 18, "女") print(json.dumps(oneman, default=human2dict)) json_str = '{"name": "如花", "age": 18, "sex": "女"}' print(json.loads(json_str, object_hook=dict2human))
我们仔细思考一下,自定义对象的属性是什么,其实自定义对象的属性最终还是由 Python 内置的数据类型表示的。我们对自定义对象进行序列化,本质是就是对对象的所有属性进行序列化,这些属性最终是由 Python 内置的数据类型表示的,我们只需要序列化这些数据就可以了,无论我们是把这些序列化后的数据存储在磁盘上 还是通过网络发送给其它机器,只需要存储或发送对象的所有属性即可
import json class Human(object): def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex oneman = Human('如花', 18, "女") onemandata = {"name": oneman.name, "age": oneman.age, "sex": oneman.sex} seqdata = json.dumps(onemandata) # 序列化对象含有的属性 print(seqdata) reseqonemandata = json.loads(seqdata) # 反序列化 print(reseqonemandata)
时间转为json的两个解决方法
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.cls代表类本身
``default(obj)`` is a function that should return a serializable version
of obj or raise TypeError. The default simply raises TypeError.
1、用类
def test(self): js = { 'test5': datetime.datetime.now(), } print(js) result = json.dumps(js, cls=CJsonEncoder) print(result) class CJsonEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, datetime.date): return obj.strftime('%Y-%m-%d') else: return json.JSONEncoder.default(self, obj)
2、用函数
def json_serial(obj): if isinstance(obj,datetime.datetime): serial=obj.isoformat() return serial elif isinstance(obj,datetime.date): serial=obj.isoformat() return serial else: return json.JSONEncoder.default(obj) js = { 'test5': datetime.datetime.now(), } print json.dumps(js, default=json_serial)