Heim Backend-Entwicklung Python-Tutorial Detaillierte Erläuterung der Python-Datenserialisierung (JSON, Pickle, Shelve)

Detaillierte Erläuterung der Python-Datenserialisierung (JSON, Pickle, Shelve)

Apr 20, 2017 am 09:58 AM
json pickle python 序列化

In diesem Artikel wird hauptsächlich die Datenserialisierung in Python vorgestellt. In diesem Abschnitt werden mehrere integrierte Module von Python für die Datenserialisierung vorgestellt.

1. Vorwort

1 Jede Programmiersprache verfügt über eigene Datentypen. Objektorientierte Programmiersprachen ermöglichen es Entwicklern auch, Datentypen (z. B. benutzerdefinierte Klassen) anzupassen, und das Gleiche gilt für Python. Oftmals haben wir solche Anforderungen:

Verschiedene Datentypen im Speicher über das Netzwerk an andere Maschinen oder Clients übertragen

  1. Verschiedene Daten speichern Datenformat

  2. Wenn wir Daten übertragen möchten Um ein System über das Netzwerk mit anderen Systemen oder Clients zu verbinden, müssen wir die Daten normalerweise zuerst in Zeichenfolgen oder Byte-Strings konvertieren und ein einheitliches Datenformat angeben, damit das Datenempfangsende die Bedeutung dieser Daten korrekt analysieren und verstehen kann. XML ist ein Datenaustauschformat, das in der Anfangszeit häufig verwendet wurde. Heutzutage wird häufig JSON (Javascript Object Notation) verwendet, ein leichtes Datenaustauschformat . Im Vergleich zu XML ist JSON einfacher, leichter zu lesen und zu schreiben und einfacher von Maschinen zu analysieren und zu generieren. Darüber hinaus können wir auch das intern verwendete Datenaustauschformat individuell anpassen.

  3. Wenn Sie die Daten auf der lokalen Festplatte speichern möchten, ist dieser Teil der Daten normalerweise nur für die interne Verwendung des Systems bestimmt. Daher müssen das Datenkonvertierungsprotokoll und das konvertierte Datenformat nicht dem Standard entsprechen und einheitlich. Solange das System nur intern korrekt identifiziert werden muss. Allerdings ändert sich das Konvertierungsprotokoll innerhalb des Systems normalerweise mit der Aktualisierung der Programmiersprachenversion (verbessert den Algorithmus, verbessert die Effizienz), sodass es normalerweise zu Kompatibilitätsproblemen zwischen dem Konvertierungsprotokoll und der Programmiersprachenversion kommt ein Beispiel.

3. Serialisierung/Deserialisierung

Konvertieren Sie Objekte in ein Datenformat, das über das Netzwerk übertragen oder auf einer lokalen Festplatte gespeichert werden kann (z. B als: XML, JSON oder eine Byte-Zeichenfolge in einem bestimmten Format) wird als Serialisierung bezeichnet, andernfalls als Deserialisierung.

4. Verwandte Module In diesem Abschnitt werden mehrere integrierte Module in Python für die Datenserialisierung vorgestellt:

2. JSON-Modul

Die meisten Programmiersprachen bieten Schnittstellen für die Verarbeitung von JSON-Daten und stellen es als zur Verfügung Integriertes Modul, zur Verwendung ist kein Download erforderlich.

模块名称 描述 提供的api
json 用于实现Python数据类型与通用(json)字符串之间的转换 dumps()、dump()、loads()、load()
pickle 用于实现Python数据类型与Python特定二进制格式之间的转换 dumps()、dump()、loads()、load()
shelve 专门用于将Python数据类型的持久化到磁盘,shelf是一个类似dict的对象,操作十分便捷 open()

1. Serialisierung und Deserialisierung Die Prozesse der Serialisierung und Deserialisierung des Python-JSON-Moduls werden als Codierung bzw. Decodierung bezeichnet.

Kodierung: Konvertieren Sie ein Python-Objekt in einen JSON-String Dekodierung: Konvertieren Sie einen JSON-String in ein Python-Objekt

    Das JSON-Modul bietet die folgenden zwei Methoden für Serialisierungs- und Deserialisierungsvorgänge:
  1. Darüber hinaus bietet das JSON-Modul zwei zusätzliche Methoden, die dies ermöglichen Wir können die serialisierten JSON-Daten direkt in einer Datei speichern und die JSON-Daten in der Datei direkt zur Deserialisierung lesen:



# 序列化:将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)
Nach dem Login kopieren
2. Datentypkorrespondenz zwischen JSON und Python


Python zu JSON

JSON zu Python

JSONPython
objectdict
arraylist
stringstr
number(int)int
number(real)float
trueTrue
falseFalse
nullNone

说明:

  1. Python dict中的非字符串key被转换成JSON字符串时都会被转换为小写字符串;

  2. Python中的tuple,在序列化时会被转换为array,但是反序列化时,array会被转化为list;

  3. 由以上两点可知,当Python对象中包含tuple数据或者包含dict,且dict中存在非字符串的key时,反序列化后得到的结果与原来的Python对象是不一致的;

  4. 对于Python内置的数据类型(如:str, unicode, int, float, bool, None, list, tuple, dict)json模块可以直接进行序列化/反序列化处理;对于自定义类的对象进行序列化和反序列化时,需要我们自己定义一个方法来完成定义object和dict之间进行转化。

3. 实例:内置数据类型序列化/反序列化

序列化


# 序列化
>>> 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]}'
Nach dem Login kopieren

sort_keys参数: 表示序列化时是否对dict的key进行排序(dict默认是无序的)


# 序列化并对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]}'
Nach dem Login kopieren

indent参数: 表示缩进的意思,它可以使得数据存储的格式变得更加优雅、可读性更强;如果indent是一个非负整数或字符串,则JSON array元素和object成员将会被以相应的缩进级别进行打印输出;如果indent是0或负数或空字符串,则将只会插入换行,不会有缩进。


# 序列化并对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
 ]
}
Nach dem Login kopieren

separators参数: 尽管indent参数可以使得数据存储的格式变得更加优雅、可读性更强,但是那是通过添加一些冗余的空白字符进行填充的。当json被用于网络数据通信时,应该尽可能的减少无用的数据传输,这样可以节省贷款并加快数据传输速度。json模块序列化Python对象后得到的json字符串中的','号和':'号分隔符后默认都会附加一个空白字符,我们可以通过separators参数重新指定分隔符,从而去除无用的空白字符;

  1. 该参数的值应该是一个tuple(item_separator, key_separator)

  2. 如果indent是None,其默认值为(', ', ': ')

  3. 如果indent不为None,则默认值为(',', ': ')

  4. 我们可以通过为separator赋值为(',', ':')来消除空白字符


>>> 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]}'
Nach dem Login kopieren

反序列化


# 反序列化
>>> 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}
Nach dem Login kopieren

dump()与load()函数示例


# 序列化到文件中
>>> 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]}
Nach dem Login kopieren

需要说明的是: 如果试图使用相同的fp重复调用dump()函数去序列化多个对象(或序列化同一个对象多次),将会产生一个无效的JSON文件,也就是说对于一个fp只能调用一次dump()。

4. 实例:自定义数据类型的序列化/反序列化

Python是面向对象的编程语言,我们可以自定义需要的数据类型;实际工作中,我们常常会用到自定义数据类型的序列化与反序列化操作。要实现自定义数据类型的序列化与反序列化有两种方式:

  1. 通过转换函数实现

  2. 通过继承JSONEncoder和JSONDecoder类实现

首先来自定义一个数据类型


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)
Nach dem Login kopieren
Nach dem Login kopieren

直接调用dumps()方法会引发TypeError错误:


>>> 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
Nach dem Login kopieren

上面的异常信息中指出:stu对象不可以被序列化为JSON个数的数据。那么我们分别通过“编写转换函数” 和 “继承JSONEncoder和JSONDecoder类” 来实现对这个自定义数据类型的JSON序列化和反序列化。

方法1:编写转换函数

那么这个转换函数要完成哪两个数据类型之间的转换呢? 从上面列出的JSON与Python数据类型的对应表中可知,JSON中的object对应的是Python中的dict,因此要对Python中的自定义数据类型的对象进行序列化,就需要先把这个对象转换成json模块可以直接进行序列化dict类型。由此可知,这个转换函数是要完成的是Python对象(不是JSON对象)与dict之间的相互转换,且序列化时转换过程是“Python对象 --> dict --> JSON object”,反序列化的过程是“JSON object -> dict --> Python对象”。所以,我们需要编写两个转换函数来分别实现序列化和反序列化时的转换过程。


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
Nach dem Login kopieren

继承JSONEncoder实现反序列化时还有一个额外的作用,就是可以通过iterencode()方法把一个很大的数据对象分多次进行序列化,这对于网络传输、磁盘持久化等情景非常有用。


>>> for chunk in MyJSONEncoder().iterencode(stu):
...  print(chunk)
...
{
"class"
:
"Student"
,
"name"
:
"Tom"
,
"module"
:
"main"
,
"sno"
:
1
,
"age"
:
19
}
Nach dem Login kopieren

大数据对象序列化网络传输伪代码:


for chunk in JSONEncoder().iterencode(bigobject):
 mysocket.write(chunk)
Nach dem Login kopieren

序列化测试:


>>> 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"}'
Nach dem Login kopieren

json.dumps(stu, default=obj2dict) 等价于 json.dumps(obj2dict(stu))

反序列化测试:


>>> 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]
Nach dem Login kopieren

json.loads(JSON_STR, object_hook=dict2obj) 等价于 dict2obj(json.loads(JSON_STR))

方法2:继承JSONEncoder和JSONDecoder实现子类


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
Nach dem Login kopieren

序列化测试:


>>> 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}'
Nach dem Login kopieren

反序列化测试:


>>> MyJSONDecoder().decode('{"sno": 1, "module": "main", "age": 19, "class": "Student", "name": "Tom"}')
Student [name: Tom, age: 19, sno: 1]
Nach dem Login kopieren

说明: 经过测试发现MyJSONDecoder().decode(JSON_STR) json.loads(JSON_STR, object_hook=dict2obj) 只能在Python 2.7上正确执行,在Python 3.5上无法正确执行;而 json.loads(JSON_STR, cls=MyJSONDecoder) 无论在Python 2.7还是在Python 3.5上都无法正确执行。这说明json模块对于自定义数据类型的反序列化支持还是比较有限的,但是我们也可以通过json.loads(JSON_STR)函数,不指定cls参数来得到一个dict对象,然后自己完成dict到object的转换。

三、pickle模块

pickle模块实现了用于对Python对象结构进行 序列化 和 反序列化 的二进制协议,与json模块不同的是pickle模块序列化和反序列化的过程分别叫做 pickling 和 unpickling:

  1. pickling: 是将Python对象转换为字节流的过程;

  2. unpickling: 是将字节流二进制文件或字节对象转换回Python对象的过程;

1. pickle模块与json模块对比

  1. JSON是一种文本序列化格式(它输出的是unicode文件,大多数时候会被编码为utf-8),而pickle是一个二进制序列化格式;

  2. JOSN是我们可以读懂的数据格式,而pickle是二进制格式,我们无法读懂;

  3. JSON是与特定的编程语言或系统无关的,且它在Python生态系统之外被广泛使用,而pickle使用的数据格式是特定于Python的;

  4. 默认情况下,JSON只能表示Python内建数据类型,对于自定义数据类型需要一些额外的工作来完成;pickle可以直接表示大量的Python数据类型,包括自定数据类型(其中,许多是通过巧妙地使用Python内省功能自动实现的;复杂的情况可以通过实现specific object API来解决)

2. pickle模块使用的数据流格式

上面提到,pickle使用的数据格式是特定于Python的。这使得它不受诸如JSON或XDR的外部标准限值,但是这也意味着非Python程序可能无法重建pickled Python对象。默认情况下,pickle数据格式使用相对紧凑的二进制表示。如果需要最佳大小特征,可以有效的压缩pickled数据。pickletools模块包含可以用于对pickle生成的数据流进行分析的工具。目前有5种不同的协议可以用于pickle。使用的协议越高,就需要更新的Python版本去读取pickle产生的数据:

  1. 协议v0是原始的“人类可读”协议,并且向后倩蓉早期的Python版本;

  2. 协议v1是一个旧的二进制格式,也与早期版本的Python兼容;

  3. 协议v2在Python 2.3中引入,它提供更高效的pickling;

  4. 协议v3是在Python 3.0添加的协议,它明确支持bytes对象,且不能被Python 2.x 进行unpickle操作;这是默认协议,也是当需要兼容其他Python 3版本时被推荐使用的协议;

  5. 协议4是在Python 3.4添加的协议,它添加了对极大对象的支持,pickling更多种类的对象,以及一些数据格式的优化。

说明: Python 2.x中默认使用的是协议v0,如果协议指定为赋值或HIGHEST_PROTOCOL,将使用当前可用的最高协议版本;Python 3.x中默认使用的是协议v3,它兼容其他Python 3版本,但是不兼容Python 2。

注意: 序列化(Serialization)是一个比持久化(Persistence)更加原始的概念;虽然pickle可以读写文件对象,但是它不处理持久化对象的命名问题,也不处理对持久化对象的并发访问问题(甚至更复杂的问题)。pickle模块可以将复杂对象转换为字节流,并且可以将字节流转换为具有相同内部结构的对象。或许最可能对这些字节流做的事情是将它们写入文件,但是也可以对它们进行网络传输或将它们存储在数据库中。shelve模块提供了一个简单的接口用于在DBM风格的数据库文件上对对象进行pickle和unpickle操作。

3. pickle模块提供的相关函数

pickle模块提供的几个序列化/反序列化的函数与json模块基本一致:


# 将指定的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")
Nach dem Login kopieren

说明: 上面这几个方法参数中,*号后面的参数都是Python 3.x新增的,目的是为了兼容Python 2.x,具体用法请参看官方文档。

4. 实例:内置数据类型的序列化/反序列化

Python 2.x


>>> 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]}
Nach dem Login kopieren

Python 3.x


>>> 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}
Nach dem Login kopieren

dump()与load()


>>> 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}
>>>
Nach dem Login kopieren

说明:

  1. 默认情况下Python 2.x中pickled后的数据是字符串形式,需要将它转换为字节对象才能被Python 3.x中的pickle.loads()反序列化;Python 3.x中pickling所使用的协议是v3,因此需要在调用pickle.dumps()时指定可选参数protocol为Python 2.x所支持的协议版本(0,1,2),否则pickled后的数据不能被被Python 2.x中的pickle.loads()反序列化;

  2. Python 3.x中pickle.dump()和pickle.load()方法中指定的文件对象,必须以二进制模式打开,而Python 2.x中可以以二进制模式打开,也可以以文本模式打开。

5. 实例:自定义数据类型的序列化/反序列化

首先来自定义一个数据类型:


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)
Nach dem Login kopieren
Nach dem Login kopieren

pickle模块可以直接对自定数据类型进行序列化/反序列化操作,无需编写额外的处理函数或类。


>>> 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]
Nach dem Login kopieren

四、shelve模块

shelve是一个简单的数据存储方案,类似key-value数据库,可以很方便的保存python对象,其内部是通过pickle协议来实现数据序列化。shelve只有一个open()函数,这个函数用于打开指定的文件(一个持久的字典),然后返回一个shelf对象。shelf是一种持久的、类似字典的对象。它与“dbm”的不同之处在于,其values值可以是任意基本Python对象--pickle模块可以处理的任何数据。这包括大多数类实例、递归数据类型和包含很多共享子对象的对象。keys还是普通的字符串。


open(filename, flag='c', protocol=None, writeback=False)
Nach dem Login kopieren

flag 参数表示打开数据存储文件的格式,可取值与dbm.open()函数一致:

描述
'r'以只读模式打开一个已经存在的数据存储文件
'w'以读写模式打开一个已经存在的数据存储文件
'c'以读写模式打开一个数据存储文件,如果不存在则创建
'n'总是创建一个新的、空数据存储文件,并以读写模式打开

protocol 参数表示序列化数据所使用的协议版本,默认是pickle v3;

writeback 参数表示是否开启回写功能。

我们可以把shelf对象当dict来使用--存储、更改、查询某个key对应的数据,当操作完成之后,调用shelf对象的close()函数即可。当然,也可以使用上下文管理器(with语句),避免每次都要手动调用close()方法。

实例:内置数据类型操作


# 保存数据
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)
Nach dem Login kopieren

输出结果:

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'])
Nach dem Login kopieren

输出结果:
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. 建议

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

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

  3. 需要将大量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()

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Python-Datenserialisierung (JSON, Pickle, Shelve). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. Crossplay haben?
1 Monate vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

PHP und Python: Code Beispiele und Vergleich PHP und Python: Code Beispiele und Vergleich Apr 15, 2025 am 12:07 AM

PHP und Python haben ihre eigenen Vor- und Nachteile, und die Wahl hängt von den Projektbedürfnissen und persönlichen Vorlieben ab. 1.PHP eignet sich für eine schnelle Entwicklung und Wartung großer Webanwendungen. 2. Python dominiert das Gebiet der Datenwissenschaft und des maschinellen Lernens.

Python gegen JavaScript: Community, Bibliotheken und Ressourcen Python gegen JavaScript: Community, Bibliotheken und Ressourcen Apr 15, 2025 am 12:16 AM

Python und JavaScript haben ihre eigenen Vor- und Nachteile in Bezug auf Gemeinschaft, Bibliotheken und Ressourcen. 1) Die Python-Community ist freundlich und für Anfänger geeignet, aber die Front-End-Entwicklungsressourcen sind nicht so reich wie JavaScript. 2) Python ist leistungsstark in Bibliotheken für Datenwissenschaft und maschinelles Lernen, während JavaScript in Bibliotheken und Front-End-Entwicklungsbibliotheken und Frameworks besser ist. 3) Beide haben reichhaltige Lernressourcen, aber Python eignet sich zum Beginn der offiziellen Dokumente, während JavaScript mit Mdnwebdocs besser ist. Die Wahl sollte auf Projektbedürfnissen und persönlichen Interessen beruhen.

Wie ist die GPU -Unterstützung für Pytorch bei CentOS? Wie ist die GPU -Unterstützung für Pytorch bei CentOS? Apr 14, 2025 pm 06:48 PM

Aktivieren Sie die Pytorch -GPU -Beschleunigung am CentOS -System erfordert die Installation von CUDA-, CUDNN- und GPU -Versionen von Pytorch. Die folgenden Schritte führen Sie durch den Prozess: Cuda und Cudnn Installation Bestimmen Sie die CUDA-Version Kompatibilität: Verwenden Sie den Befehl nvidia-smi, um die von Ihrer NVIDIA-Grafikkarte unterstützte CUDA-Version anzuzeigen. Beispielsweise kann Ihre MX450 -Grafikkarte CUDA11.1 oder höher unterstützen. Download und installieren Sie Cudatoolkit: Besuchen Sie die offizielle Website von Nvidiacudatoolkit und laden Sie die entsprechende Version gemäß der höchsten CUDA -Version herunter und installieren Sie sie, die von Ihrer Grafikkarte unterstützt wird. Installieren Sie die Cudnn -Bibliothek:

Detaillierte Erklärung des Docker -Prinzips Detaillierte Erklärung des Docker -Prinzips Apr 14, 2025 pm 11:57 PM

Docker verwendet Linux -Kernel -Funktionen, um eine effiziente und isolierte Anwendungsumgebung zu bieten. Sein Arbeitsprinzip lautet wie folgt: 1. Der Spiegel wird als schreibgeschützte Vorlage verwendet, die alles enthält, was Sie für die Ausführung der Anwendung benötigen. 2. Das Union File System (UnionFS) stapelt mehrere Dateisysteme, speichert nur die Unterschiede, speichert Platz und beschleunigt. 3. Der Daemon verwaltet die Spiegel und Container, und der Kunde verwendet sie für die Interaktion. 4. Namespaces und CGroups implementieren Container -Isolation und Ressourcenbeschränkungen; 5. Mehrere Netzwerkmodi unterstützen die Containerverbindung. Nur wenn Sie diese Kernkonzepte verstehen, können Sie Docker besser nutzen.

Miniopen CentOS -Kompatibilität Miniopen CentOS -Kompatibilität Apr 14, 2025 pm 05:45 PM

Minio-Objektspeicherung: Hochleistungs-Bereitstellung im Rahmen von CentOS System Minio ist ein hochleistungsfähiges, verteiltes Objektspeichersystem, das auf der GO-Sprache entwickelt wurde und mit Amazons3 kompatibel ist. Es unterstützt eine Vielzahl von Kundensprachen, darunter Java, Python, JavaScript und Go. In diesem Artikel wird kurz die Installation und Kompatibilität von Minio zu CentOS -Systemen vorgestellt. CentOS -Versionskompatibilitätsminio wurde in mehreren CentOS -Versionen verifiziert, einschließlich, aber nicht beschränkt auf: CentOS7.9: Bietet einen vollständigen Installationshandbuch für die Clusterkonfiguration, die Umgebungsvorbereitung, die Einstellungen von Konfigurationsdateien, eine Festplattenpartitionierung und Mini

Wie man eine verteilte Schulung von Pytorch auf CentOS betreibt Wie man eine verteilte Schulung von Pytorch auf CentOS betreibt Apr 14, 2025 pm 06:36 PM

Pytorch Distributed Training on CentOS -System erfordert die folgenden Schritte: Pytorch -Installation: Die Prämisse ist, dass Python und PIP im CentOS -System installiert sind. Nehmen Sie abhängig von Ihrer CUDA -Version den entsprechenden Installationsbefehl von der offiziellen Pytorch -Website ab. Für CPU-Schulungen können Sie den folgenden Befehl verwenden: PipinstallTorChTorChVisionTorChaudio Wenn Sie GPU-Unterstützung benötigen, stellen Sie sicher, dass die entsprechende Version von CUDA und CUDNN installiert ist und die entsprechende Pytorch-Version für die Installation verwenden. Konfiguration der verteilten Umgebung: Verteiltes Training erfordert in der Regel mehrere Maschinen oder mehrere Maschinen-Mehrfach-GPUs. Ort

So wählen Sie die Pytorch -Version auf CentOS aus So wählen Sie die Pytorch -Version auf CentOS aus Apr 14, 2025 pm 06:51 PM

Bei der Installation von PyTorch am CentOS -System müssen Sie die entsprechende Version sorgfältig auswählen und die folgenden Schlüsselfaktoren berücksichtigen: 1. Kompatibilität der Systemumgebung: Betriebssystem: Es wird empfohlen, CentOS7 oder höher zu verwenden. CUDA und CUDNN: Pytorch -Version und CUDA -Version sind eng miteinander verbunden. Beispielsweise erfordert Pytorch1.9.0 CUDA11.1, während Pytorch2.0.1 CUDA11.3 erfordert. Die Cudnn -Version muss auch mit der CUDA -Version übereinstimmen. Bestimmen Sie vor der Auswahl der Pytorch -Version unbedingt, dass kompatible CUDA- und CUDNN -Versionen installiert wurden. Python -Version: Pytorch Official Branch

So aktualisieren Sie Pytorch auf die neueste Version von CentOS So aktualisieren Sie Pytorch auf die neueste Version von CentOS Apr 14, 2025 pm 06:15 PM

Das Aktualisieren von PyTorch auf der neuesten Version von CentOS kann die folgenden Schritte ausführen: Methode 1: Aktualisieren von PIP mit PIP: Stellen Sie zunächst sicher, dass Ihr PIP die neueste Version ist, da ältere Versionen von PIP möglicherweise nicht in der Lage sind, die neueste Version von PyTorch ordnungsgemäß zu installieren. Pipinstall-upgradePip Die alte Version von Pytorch (falls installiert): PipuninstallTorChTorChVisionTorChaudio-Installation Neueste

See all articles