•  


Python之?据序列化(json、pickle、shelve) - 云游道士 - 博客?

Python之?据序列化(json、pickle、shelve)

本??容


  1. 前言
  2. json模?
  3. pickle模?
  4. shelve模?
  5. ??

一、前言


1. ??需求

每??程?言都有各自的?据?型,其中面向?象的?程?言?允???者自定??据?型(如:自定??),Python也是一?。?多?候我??有??的需求:

  • 把?存中的各??据?型的?据通????送?其?机器或客?端;
  • 把?存中的各??据?型的?据保存到本地磁?持久化;

2.?据格式

如果要?一?系??的?据通??????其?系?或客?端,我?通常都需要先把?些?据?化?字符串或字?串,而且需要?定一??一的?据格式才能??据接收端正?解析?理解?些?据的含?。 XML 是早期被?泛使用的?据交?格式,在早期的系?集成?文中?常可以看到?的身影;如今大家使用更多的?据交?格式是 JSON(JavaScript Object Notation) ,?是一??量?的?据交?格式。JSON相?于XML而言,更加加?、易于??和??,同?也易于机器解析和生成。除此之外,我?也可以自定??部使用的?据交?格式。

如果是想把?据持久化到本地磁?,?部分?据通常只是供系??部使用,因此?据????以及??后的?据格式也就不要求是?准、?一的,只要本系??部能?正????可。但是,系??部的????通常??着?程?言版本的升?而?生?化(改?算法、提高效率),因此通常?涉及??????程?言的版本兼容??,下面要介?的pickle??就是??一?例子。

3. 序列化/反序列化

??象???可通?????或可以存?到本地磁?的?据格式(如:XML、JSON或特定格式的字?串)的?程??序列化;反之,???反序列化。

4.相?模?

本?要介?的就是Python?置的??用于?行?据序列化的模?:

模?名? | 描述 | 提供的api

  • | - | -
    json | 用于??Python?据?型?通用(json)字符串之?的?? | dumps()、dump()、loads()、load()
    pickle | 用于??Python?据?型?Python特定二?制格式之?的?? | dumps()、dump()、loads()、load()
    shelve | ??用于?Python?据?型的?据持久化到磁?,shelve是一??似dict的?象,操作十分便捷 | open()

二、json模?


大部分?程?言都?提供?理json?据的接口,Python 2.6?始加入了json模?,且把?作?一??置模?提供,无需下??可使用。

1. 序列化?反序列化

Python的JSON模? 序列化?反序列化的?程分?叫做:encoding 和 decoding。

  • encoding: 把Python?象??成JSON字符串
  • decoding: 把JSON字符串??成python?象

json模?提供了以下??方法??行序列化和反序列化操作:

# 序列化:?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)

除此之外,json模??提供了???外的方法允?我?直接?序列化后得到的json?据保存到文件中,以及直接?取文件中的json?据?行反序列化操作:

# 序列化:?Python?象??成json字符串?存?到文件中
dump(obj, fp, 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?象
load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

2. JSON?Python之??据?型???系

Python?JSON

Python | JSON

  • | -
    dict | Object
    list, tuple | array
    str | string
    int, float, int- & float-derived Enums | numbers
    True | true
    False | false
    None | null

JSON?Python

JSON | Python

  • | -
    object | dict
    array | list
    string | str
    number(int) | int
    number(real) | float
    true | True
    false | False
    null | None

?明:

  • Python dict中的非字符串key被??成JSON字符串?都?被???小?字符串;
  • Python中的tuple,在序列化??被???array,但是反序列化?,array?被?化?list;
  • 由以上?点可知,?Python?象中包含tuple?据或者包含dict,且dict中存在非字符串的key?,反序列化后得到的?果?原?的Python?象是不一致的;
  • ?于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]}'

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]}'

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
    ]
}

separators??: ?管indent??可以使得?据存?的格式?得更加?雅、可?性更强,但是那是通?添加一些冗余的空白字符?行?充的。?json被用于???据通信?,???可能的?少无用的?据??,??可以?省???加快?据??速度。json模?序列化Python?象后得到的json字符串中的','?和':'?分隔符后默?都?附加一?空白字符,我?可以通?separators??重新指定分隔符,?而去除无用的空白字符;

  • ???的???是一?tuple(item_separator, key_separator)
  • 如果indent是None,其默???(', ', ': ')
  • 如果indent不?None,?默???(',', ': ')
  • 我?可以通??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]}'

ensure_ascii??: ????的??True(默??)?,?出中的所有非ASCII字符(比如中文)都?被??成'\uXXXX'?成的序列,得到的?果是一?完全由ASCII字符?成的str?例。如果我?想得到一?人?可?的?出?果,需要把ensure_ascii??的??置?False。

>>> stu={"name": "小明", "age" : 16}
>>> stu_json = json.dumps(stu)
>>> print(stu_json)
'{"name": "\u5c0f\u660e", "age": 16}'
>>> stu_json01 = json.dumps(stu, ensure_ascii=False)
>>> print(stu_json01)
'{"name": "小明", "age": 16}'

?明: ??上'\uXXXX'是Unicode字符??的?存???,??存??名??"unicode-escape",我?可以通? unicodestr.encode('unicode-escape') decode('unicode-escape') ?完成Unicode字符串?Unicode?存??序列?行相互??,如下所示:

>>> str1 = "hello 中?"
>>> str2 = str1.encode("unicode_escape")
>>> print(str2)
b'hello \\u4e2d\\u56fd'
>>> str3 = str2.decode("unicode_escape")
>>> print(str3)
hello 中?

注意str2是字?串,不是字符串,因此\u前面需要再加一?反斜?做??。我?把str2??成字符串就是我?熟悉的格式了:

>>> str4=str2.decode("utf-8")
>>> print(str4)
hello \u4e2d\u56fd
>>>

反序列化

# 反序列化
>>> 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}

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]}

需要?明的是: 如果??使用相同的fp重??用dump()函?去序列化多??象(或序列化同一??象多次),???生一?无效的JSON文件,也就是??于一?fp只能?用一次dump()。

4. ?例:自定??据?型的序列化/反序列化

Python是面向?象的?程?言,我?可以自定?需要的?据?型;??工作中,我?常常?用到自定??据?型的序列化?反序列化操作。要??自定??据?型的序列化?反序列化有??方式:

  • 通???函???
  • 通??承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)

直接?用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

上面的?常信息中指出: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
序列化??:
>>> 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.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]

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
序列化??:
>>> 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]

?明: ?????? 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的??。

?承JSONEncoder??序列化??有一??外的作用,就是可以通?iterencode()方法把一??大的?据?象分多次?行序列化,??于????、磁?持久化等情景非常有用。

>>> 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)

三、pickle模?


pickle模???了用于?Python?象???行 序列化 和 反序列化 的二?制??,?json模?不同的是pickle模?序列化和反序列化的?程分?叫做 pickling 和 unpickling:

  • pickling: 是?Python?象???字?流的?程;
  • unpickling: 是?字?流二?制文件或字??象??回Python?象的?程;

1. pickle模??json模??比

  • JSON是一?文本序列化格式(??出的是unicode文件,大多??候?被???utf-8),而pickle是一?二?制序列化格式;
  • JOSN是我?可以??的?据格式,而pickle是二?制格式,我?无法??;
  • JSON是?特定的?程?言或系?无?的,且?在Python生?系?之外被?泛使用,而pickle使用的?据格式是特定于Python的;
  • 默?情?下,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?生的?据:

  • ??v0是原始的“人?可?”??,?且向后兼容早期的Python版本;
  • ??v1是一??的二?制格式,也?早期版本的Python兼容;
  • ??v2在Python 2.3中引入,?提供更高效的pickling;
  • ??v3是在Python 3.0添加的??,?明?支持bytes?象,且不能被Python 2.x ?行unpickle操作;?是默???,也是?需要兼容其他Python 3版本?被推?使用的??;
  • ??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")

?明: 上面???方法??中,*?后面的??都是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]}

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}

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}
>>>

?明:

  • 默?情?下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()反序列化;
  • 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)

pickle模?可以直接?自定?据?型?行序列化/反序列化操作,无需???外的?理函?或?。

>>> stu = Student('Tom', 19, 1)
>>> print(stu)
Student [name: Tom, age: 19, sno: 1]

# 序列化
>>> var_b = pickle.dumps(stu)
>>> var_b
b'\x80\x03c__main__\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]

四、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()方法。

?例:?置?据?型操作

# 保存?据
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]

五、??


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()

??交流群:666948590

posted @ 2017-03-17 08:10   云游道士   ??( 58874 )  ??( 7 ??   收藏   ??
- "漢字路" 한글한자자동변환 서비스는 교육부 고전문헌국역지원사업의 지원으로 구축되었습니다.
- "漢字路" 한글한자자동변환 서비스는 전통문화연구회 "울산대학교한국어처리연구실 옥철영(IT융합전공)교수팀"에서 개발한 한글한자자동변환기를 바탕하여 지속적으로 공동 연구 개발하고 있는 서비스입니다.
- 현재 고유명사(인명, 지명등)을 비롯한 여러 변환오류가 있으며 이를 해결하고자 많은 연구 개발을 진행하고자 하고 있습니다. 이를 인지하시고 다른 곳에서 인용시 한자 변환 결과를 한번 더 검토하시고 사용해 주시기 바랍니다.
- 변환오류 및 건의,문의사항은 juntong@juntong.or.kr로 메일로 보내주시면 감사하겠습니다. .
Copyright ⓒ 2020 By '전통문화연구회(傳統文化硏究會)' All Rights reserved.
 한국   대만   중국   일본