您好,登錄后才能下訂單哦!
這篇文章主要為大家展示了“Python中常見序列化操作的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Python中常見序列化操作的示例分析”這篇文章吧。
0x00 marshal
marshal使用的是與Python語言相關但與機器無關的二進制來讀寫Python對象的。這種二進制的格式也跟Python語言的版本相關,marshal序列化的格式對不同的版本的Python是不兼容的。
marshal一般用于Python內部對象的序列化。
一般地包括:
基本類型 booleans, integers,floating point numbers,complex numbers
序列集合類型 strings, bytes, bytearray, tuple, list, set, frozenset, dictionary
code對象 code object
其它類型 None, Ellipsis, StopIteration
marshal的主要作用是對Python“編譯”的.pyc文件讀寫的支持。這也是marshal對Python版本不兼容的原因。開發者如果要使用序列化/反序列化,那么應該使用pickle模塊。
常見的方法
marshal.dump(value, file[, version])
序列化一個對象到文件中
marshal.dumps(value[, version])
序列化一個對象并返回一個bytes對象
marshal.load(file)
從文件中反序列化一個對象
marshal.loads(bytes)
從bytes二進制數據中反序列化一個對象
0x01 pickle
pickle模塊也能夠以二進制的方式對Python對象進行讀寫。相比marshal提供基本的序列化能力,pickle的序列化應用更加廣泛。
pickle序列化后的數據也是與Python語言相關的,即其它語言例如Java無法讀取由Python通過pickle序列化的二進制數據。如果要使用與語言無法的序列化那么我們應該使用json。下文將會說明。
能被pickle序列化的數據類型有:
None, True, and False
integers, floating point numbers, complex numbers
strings, bytes, bytearrays
tuples, lists, sets, and dictionaries 以及包含可以被pickle序列化對象
在模塊頂層定義的函數對象 (使用 def定義的, 而不是 lambda表達式)
在模塊頂層定義內置函數
在模式頂層定義的類
一個類的__dict__包含了可序列化的對象或__getstate__()方法返回了能夠被序列化的對象
如果pickle一個不支持序列化的對象時將會拋出PicklingError。
常見的方法
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
將obj對象序列化到一個file文件中,該方法與Pickler(file, protocol).dump(obj)等價。
pickle.dumps(obj, protocol=None, *, fix_imports=True)
將obj對象序列化成bytes二進制數據。
pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
從file文件中反序列化一個對象,該方法與Unpickler(file).load()等價。
pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")
從二進制數據bytes_object反序列化對象。
序列化例子
import pickle # 定義了一個包含了可以被序列化對象的字典 data = { 'a': [1, 2.0, 3, 4 + 6j], 'b': ("character string", b"byte string"), 'c': {None, True, False} } with open('data.pickle', 'wb') as f: # 序列化對象到一個data.pickle文件中 # 指定了序列化格式的版本pickle.HIGHEST_PROTOCOL pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)
執行之后在文件夾中多一個data.pickle文件
serialization
├── data.pickle
├── pickles.py
└── unpickles.py
反序列化例子
import pickle with open('data.pickle', 'rb') as f: # 從data.pickle文件中反序列化對象 # pickle能夠自動檢測序列化文件的版本 # 所以這里可以不用版本號 data = pickle.load(f) print(data) # 執行后結果 # {'a': [1, 2.0, 3, (4+6j)], 'b': ('character string', b'byte string'), 'c': {False, True, None}}
0x02 json
json是與語言無關,非常通用的數據交互格式。在Python它與marshal和pickle一樣擁有相似的API。
常見的方法
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)
序列化對象到fp文件中
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)
將obj序列化成json對象
json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
從文件中反序列化成一個對象
json.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與Python對象的轉化對照表
JSON | Python |
---|---|
object | dict |
list,tuple | array |
str | string |
int, float, int- & float-derived Enums | number |
True | true |
False | false |
None | null |
對于基本類型、序列、以及包含基本類型的集合類型json都可以很好的完成序列化工作。
序列化例子
>>> import json >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) '["foo", {"bar": ["baz", null, 1.0, 2]}]' >>> print(json.dumps("\"foo\bar")) "\"foo\bar" >>> print(json.dumps('\u1234')) "\u1234" >>> print(json.dumps('\\')) "\\" >>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)) {"a": 0, "b": 0, "c": 0} >>> from io import StringIO >>> io = StringIO() >>> json.dump(['streaming API'], io) >>> io.getvalue() '["streaming API"]'
反序列化例子
>>> import json >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') ['foo', {'bar': ['baz', None, 1.0, 2]}] >>> json.loads('"\\"foo\\bar"') '"foo\x08ar' >>> from io import StringIO >>> io = StringIO('["streaming API"]') >>> json.load(io) ['streaming API']
對于object的情況就復雜一些了
例如定義了復數complex對象的json文檔
complex_data.json
{ "__complex__": true, "real": 42, "imaginary": 36 }
要把這個json文檔反序列化成Python對象,就需要定義轉化的方法
# coding=utf-8 import json # 定義轉化函數,將json中的內容轉化成complex對象 def decode_complex(dct): if "__complex__" in dct: return complex(dct["real"], dct["imaginary"]) else: return dct if __name__ == '__main__': with open("complex_data.json") as complex_data: # object_hook指定轉化的函數 z = json.load(complex_data, object_hook=decode_complex) print(type(z)) print(z) # 執行結果 # <class 'complex'> # (42+36j)
如果不指定object_hook,那么默認將json文檔中的object轉成dict
# coding=utf-8 import json if __name__ == '__main__': with open("complex_data.json") as complex_data: # 這里不指定object_hook z2 = json.loads(complex_data.read()) print(type(z2)) print(z2) # 執行結果 # <class 'dict'> # {'__complex__': True, 'real': 42, 'imaginary': 36}
可以看到json文檔中的object轉成了dict對象。
一般情況下這樣使用似乎也沒什么問題,但如果對類型要求很高的場景就需要明確定義轉化的方法了。
除了object_hook參數還可以使用json.JSONEncoder
import json class ComplexEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, complex): # 如果complex對象這里轉成數組的形式 return [obj.real, obj.imag] # 默認處理 return json.JSONEncoder.default(self, obj) if __name__ == '__main__': c = json.dumps(2 + 1j, cls=ComplexEncoder) print(type(c)) print(c) # 執行結果 # <class 'str'> # [2.0, 1.0]
因為json模塊并不是對所有類型都能夠自動完成序列化的,對于不支持的類型,會直接拋出TypeError。
>>> import datetime >>> d = datetime.datetime.now() >>> dct = {'birthday':d,'uid':124,'name':'jack'} >>> dct {'birthday': datetime.datetime(2019, 6, 14, 11, 16, 17, 434361), 'uid': 124, 'name': 'jack'} >>> json.dumps(dct) Traceback (most recent call last): File "<pyshell#19>", line 1, in <module> json.dumps(dct) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumps return _default_encoder.encode(obj) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode chunks = self.iterencode(o, _one_shot=True) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode return _iterencode(o, 0) File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in default raise TypeError(f'Object of type {o.__class__.__name__} ' TypeError: Object of type datetime is not JSON serializable
對于不支持序列化的類型例如datetime以及自定義類型,就需要使用JSONEncoder來定義轉化的邏輯。
import json import datetime # 定義日期類型的JSONEncoder class DatetimeEncoder(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) if __name__ == '__main__': d = datetime.date.today() dct = {"birthday": d, "name": "jack"} data = json.dumps(dct, cls=DatetimeEncoder) print(data) # 執行結果 # {"birthday": "2019-06-14", "name": "jack"}
現在我們希望發序列化時,能夠將json文檔中的日期格式轉化成datetime.date對象,這時就需要使用到json.JSONDecoder了。
# coding=utf-8 import json import datetime # 定義Decoder解析json class DatetimeDecoder(json.JSONDecoder): # 構造方法 def __init__(self): super().__init__(object_hook=self.dict2obj) def dict2obj(self, d): if isinstance(d, dict): for k in d: if isinstance(d[k], str): # 對日期格式進行解析,生成一個date對象 dat = d[k].split("-") if len(dat) == 3: date = datetime.date(int(dat[0]), int(dat[1]), int(dat[2])) d[k] = date return d if __name__ == '__main__': d = datetime.date.today() dct = {"birthday": d, "name": "jack"} data = json.dumps(dct, cls=DatetimeEncoder) # print(data) obj = json.loads(data, cls=DatetimeDecoder) print(type(obj)) print(obj) # 執行結果 # {"birthday": "2019-06-14", "name": "jack"} # <class 'dict'> # {'birthday': datetime.date(2019, 6, 14), 'name': 'jack'}
0x03 總結一下
Python常見的序列化工具有marshal、pickle和json。marshal主要用于Python的.pyc文件,并與Python版本相關。它不能序列化用戶定義的類。
pickle是Python對象的序列化工具則比marshal更通用些,它可以兼容Python的不同版本。json是一種語言無關的數據結構,廣泛用于各種網絡應用尤其在REST API的服務中的數據交互。
以上是“Python中常見序列化操作的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。