好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Python之数据序列化(json、pickle、shelve)详解

本篇文章主要介绍了Python之数据序列化,本节要介绍的就是Python内置的几个用于进行数据序列化的模块,有兴趣的可以了解一下。

# 序列化:将Python对象转换成json字符串
dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

# 反序列化:将json字符串转换成Python对象
loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) 
# 序列化:将Python对象转换成json字符串并存储到文件中
dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

# 反序列化:读取指定文件中的json字符串并转换成Python对象
load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw) 
# 序列化
>>> json.dumps({'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)})
'{"a": "str", "c": true, "b": 11.1, "e": 10, "d": null, "g": [4, 5, 6], "f": [1, 2, 3]}' 
# 序列化并对key进行排序
>>> json.dumps({'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}, sort_keys=True)
'{"a": "str", "b": 11.1, "c": true, "d": null, "e": 10, "f": [1, 2, 3], "g": [4, 5, 6]}' 
# 序列化并对key进行排序及格式化 
输出 >>> 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.dumps({'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)})
'{"a": "str", "c": true, "b": 11.1, "e": 10, "d": null, "g": [4, 5, 6], "f": [1, 2, 3]}'

>>> json.dumps({'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}, separators=(',',':'))
'{"a":"str","c":true,"b":11.1,"e":10,"d":null,"g":[4,5,6],"f":[1,2,3]}' 
# 反序列化
>>> json.loads('{"a": "str", "c": true, "b": 11.1, "e": 10, "d": null, "g": [4, 5, 6], "f": [1, 2, 3]}')
{'c': True, 'e': 10, 'a': 'str', 'g': [4, 5, 6], 'd': None, 'f': [1, 2, 3], 'b': 11.1}

>>> json.loads('{"a":"str","c":true,"b":11.1,"e":10,"d":null,"g":[4,5,6],"f":[1,2,3]}')
{'c': True, 'e': 10, 'a': 'str', 'g': [4, 5, 6], 'd': None, 'f': [1, 2, 3], 'b': 11.1} 
# 序列化到文件中
>>> with open('test.json', 'w') as fp:
...  json.dump({'a':'str中国', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}, fp, indent=4)

# 反序列化文件中的内容
>>> with open('test.json', 'r') as fp:
...  json.load(fp)
{'e': 10, 'g': [4, 5, 6], 'b': 11.1, 'c': True, 'd': None, 'a': 'str中国', 'f': [1, 2, 3]} 
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) 
>>> stu = Student('Tom', 19, 1)
>>> print(stu)
Student [name: Tom, age: 19, sno: 1]
>>>
>>> json.dumps(stu)
...
TypeError: Student [name: Tom, age: 19, sno: 1] is not JSON serializable 
def obj2dict(obj):
 d = {}
 d['class'] = obj.class.name
 d['module'] = obj.module
 d.update(obj.dict)
 return d

def dict2obj(d):
 if 'class' in d:
  class_name = d.pop('class')
  module_name = d.pop('module')
  module = import(module_name)
  class_ = getattr(module, class_name)
  args = dict((key.encode('ascii'), value) for key, value in d.items())
  instance = class_(**args)
 else:
  instance = d
 return instance 
>>> for chunk in MyJSONEncoder().iterencode(stu):
...  print(chunk)
...
{
"class"
:
"Student"
,
"name"
:
"Tom"
,
"module"
:
"main"
,
"sno"
:
1
,
"age"
:
19
} 
for chunk in JSONEncoder().iterencode(bigobject):
 mysocket.write(chunk) 
>>> import json

>>> obj2dict(stu)
{'sno': 1, 'module': 'main', 'age': 19, 'class': 'Student', 'name': 'Tom'}

>>> json.dumps(obj2dict(stu))
'{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}'

>>> json.dumps(stu, default=obj2dict)
'{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}' 
>>> json.loads('{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}')
{u'sno': 1, u'module': u'main', u'age': 19, u'name': u'Tom', u'class': u'Student'}

>>> dict2obj(json.loads('{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}'))
Student [name: Tom, age: 19, sno: 1]

>>> json.loads('{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}', object_hook=dict2obj)
Student [name: Tom, age: 19, sno: 1] 
import json

class MyJSONEncoder(json.JSONEncoder):
 def default(self, obj):
  d = {}
  d['class'] = obj.class.name
  d['module'] = obj.module
  d.update(obj.dict)
  return d

class MyJSONDecoder(json.JSONDecoder):
 def init(self):
  json.JSONDecoder.init(self, object_hook=self.dict2obj)
 
 def dict2obj(self, d):
  if 'class' in d:
   class_name = d.pop('class')
   module_name = d.pop('module')
   module = import(module_name)
   class_ = getattr(module, class_name)
   args = dict((key.encode('ascii'), value) for key, value in d.items())
   instance = class_(**args)
  else:
   instance = d
  return instance 
>>> stu = Student('Tom', 19, 1)

# 方式一:直接调用子类MyJSONEncoder的encode()方法进行序列化
>>> MyJSONEncoder().encode(stu)
'{"class": "Student", "module": "main", "name": "Tom", "age": 19, "sno": 1}'
>>> MyJSONEncoder(separators=(',', ':')).encode(stu)
'{"class":"Student","module":"main","name":"Tom","age":19,"sno":1}'

# 方式二:将子类MyJSONEncoder作为cls参数的值传递给json.dumps()函数
>>> json.dumps(stu, cls=MyJSONEncoder)
'{"class": "Student", "module": "main", "name": "Tom", "age": 19, "sno": 1}'
>>> json.dumps(stu, cls=MyJSONEncoder, separators=(',', ':'))
'{"class":"Student","module":"main","name":"Tom","age":19,"sno":1}' 
>>> MyJSONDecoder().decode('{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}')
Student [name: Tom, age: 19, sno: 1] 
# 将指定的Python对象通过pickle序列化作为bytes对象返回,而不是将其写入文件
dumps(obj, protocol=None, *, fix_imports=True)

# 将通过pickle序列化后得到的字节对象进行反序列化,转换为Python对象并返回
loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")

# 将指定的Python对象通过pickle序列化后写入打开的文件对象中,等价于`Pickler(file, protocol).dump(obj)`
dump(obj, file, protocol=None, *, fix_imports=True)

# 从打开的文件对象中读取pickled对象表现形式并返回通过pickle反序列化后得到的Python对象
load(file, *, fix_imports=True, encoding="ASCII", errors="strict") 
>>> import pickle
>>> 
>>> var_a = {'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}

# 序列化
>>> var_b = pickle.dumps(var_a)
>>> var_b
"(dp0\nS'a'\np1\nS'str'\np2\nsS'c'\np3\nI01\nsS'b'\np4\nF11.1\nsS'e'\np5\nI10\nsS'd'\np6\nNsS'g'\np7\n(I4\nI5\nI6\ntp8\nsS'f'\np9\n(lp10\nI1\naI2\naI3\nas."

# 反序列化
>>> var_c = pickle.loads(var_b)
>>> var_c
{'a': 'str', 'c': True, 'b': 11.1, 'e': 10, 'd': None, 'g': (4, 5, 6), 'f': [1, 2, 3]} 
>>> import pickle
>>>
>>> var_a = {'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}

# 序列化
>>> var_b = pickle.dumps(var_a)
>>> var_b
b'\x80\x03}q\x00(X\x01\x00\x00\x00eq\x01K\nX\x01\x00\x00\x00aq\x02X\x03\x00\x00\x00strq\x03X\x01\x00\x00\x00fq\x04]q\x05(K\x01K\x02K\x03eX\x01\x00\x00\x00gq\x06K\x04K\x05K\x06\x87q\x07X\x01\x00\x00\x00bq\x08G@&333333X\x01\x00\x00\x00cq\t\x88X\x01\x00\x00\x00dq\nNu.'

# 反序列化
>>> var_c = pickle.loads(var_b)
>>> var_c
{'e': 10, 'a': 'str', 'f': [1, 2, 3], 'g': (4, 5, 6), 'b': 11.1, 'c': True, 'd': None} 
>>> import pickle
>>>
>>> var_a = {'a':'str', 'c': True, 'e': 10, 'b': 11.1, 'd': None, 'f': [1, 2, 3], 'g':(4, 5, 6)}

# 持久化到文件
>>> with open('pickle.txt', 'wb') as f:
...  pickle.dump(var_a, f)
...

# 从文件中读取数据
>>> with open('pickle.txt', 'rb') as f:
...  var_b = pickle.load(f)
...
>>> var_b
{'e': 10, 'a': 'str', 'f': [1, 2, 3], 'g': (4, 5, 6), 'b': 11.1, 'c': True, 'd': None}
>>> 
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) 
>>> stu = Student('Tom', 19, 1)
>>> print(stu)
Student [name: Tom, age: 19, sno: 1]

# 序列化
>>> var_b = pickle.dumps(stu)
>>> var_b
b'\x80\x03cmain\nStudent\nq\x00)\x81q\x01}q\x02(X\x04\x00\x00\x00nameq\x03X\x03\x00\x00\x00Tomq\x04X\x03\x00\x00\x00ageq\x05K\x13X\x03\x00\x00\x00snoq\x06K\x01ub.'

# 反序列化
>>> var_c = pickle.loads(var_b)
>>> var_c
Student [name: Tom, age: 19, sno: 1]

# 持久化到文件
>>> with open('pickle.txt', 'wb') as f:
...  pickle.dump(stu, f)
...

# 从文件总读取数据
>>> with open('pickle.txt', 'rb') as f:
...  pickle.load(f)
...
Student [name: Tom, age: 19, sno: 1] 
# 保存数据
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) 
# 自定义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]

五、总结

1. 对比

json模块常用于编写web接口,将Python数据转换为通用的json格式传递给其它系统或客户端;也可以用于将Python数据保存到本地文件中,缺点是明文保存,保密性差。另外,如果需要保存费内置数据类型需要编写额外的转换函数或自定义类。

pickle模块和shelve模块由于使用其特有的序列化协议,其序列化之后的数据只能被Python识别,因此只能用于Python系统内部。另外,Python 2.x 和 Python
3.x 默认使用的序列化协议也不同,如果需要互相兼容需要在序列化时通过protocol参数指定协议版本。除了上面这些缺点外,pickle模块和shelve模块相对于json模块的优点在于对于自定义数据类型可以直接序列化和反序列化,不需要编写额外的转换函数或类。

shelve模块可以看做是pickle模块的升级版,因为shelve使用的就是pickle的序列化协议,但是shelve比pickle提供的操作方式更加简单、方便。shelve模块相对于其它两个模块在将Python数据持久化到本地磁盘时有一个很明显的优点就是,它允许我们可以像操作dict一样操作被序列化的数据,而不必一次性的保存或读取所有数据。

2. 建议

需要与外部系统交互时用json模块;

需要将少量、简单Python数据持久化到本地磁盘文件时可以考虑用pickle模块;

需要将大量Python数据持久化到本地磁盘文件或需要一些简单的类似数据库的增删改查功能时,可以考虑用shelve模块。

3. 附录

要实现的功能 可以使用的api 将Python数据类型转换为(json)字符串 json.dumps() 将json字符串转换为Python数据类型 json.loads() 将Python数据类型以json形式保存到本地磁盘 json.dump() 将本地磁盘文件中的json数据转换为Python数据类型 json.load() 将Python数据类型转换为Python特定的二进制格式 pickle.dumps() 将Python特定的的二进制格式数据转换为Python数据类型 pickle.loads() 将Python数据类型以Python特定的二进制格式保存到本地磁盘 pickle.dump() 将本地磁盘文件中的Python特定的二进制格式数据转换为Python数据类型 pickle.load() 以类型dict的形式将Python数据类型保存到本地磁盘或读取本地磁盘数据并转换为数据类型 shelve.open()

以上就是Python之数据序列化(json、pickle、shelve)详解的详细内容,更多请关注Gxl网其它相关文章!

查看更多关于Python之数据序列化(json、pickle、shelve)详解的详细内容...

  阅读:44次