關於我
編程界的一名小小程序猿,目前在一個創業團隊任team lead,技術棧涉及Android、Python、Java和Go,這個也是咱們團隊的主要技術棧。 聯繫:hylinux1024@gmail.comhtml
marshal
使用的是與Python
語言相關但與機器無關的二進制來讀寫Python
對象的。這種二進制的格式也跟Python
語言的版本相關,marshal
序列化的格式對不一樣的版本的Python
是不兼容的。python
marshal
通常用於Python
內部對象的序列化。linux
通常地包括:shell
booleans, integers,floating point numbers,complex numbers
strings, bytes, bytearray, tuple, list, set, frozenset, dictionary
code object
None, Ellipsis, StopIteration
marshal
的主要做用是對Python
「編譯」的.pyc
文件讀寫的支持。這也是marshal
對Python
版本不兼容的緣由。開發者若是要使用序列化/反序列化,那麼應該使用pickle
模塊。編程
marshal.dump(value, file[, version])
複製代碼
序列化一個對象到文件中json
marshal.dumps(value[, version])
複製代碼
序列化一個對象並返回一個bytes
對象小程序
marshal.load(file)
複製代碼
從文件中反序列化一個對象數組
marshal.loads(bytes)
複製代碼
從bytes
二進制數據中反序列化一個對象bash
pickle
模塊也可以以二進制的方式對Python
對象進行讀寫。相比marshal
提供基本的序列化能力,pickle
的序列化應用更加普遍。網絡
pickle
序列化後的數據也是與Python
語言相關的,即其它語言例如Java
沒法讀取由Python
經過pickle
序列化的二進制數據。若是要使用與語言沒法的序列化那麼咱們應該使用json
。下文將會說明。
能被pickle
序列化的數據類型有:
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}}
複製代碼
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'}
複製代碼
Python
常見的序列化工具備marshal
、pickle
和json
。marshal
主要用於Python
的.pyc
文件,並與Python
版本相關。它不能序列化用戶定義的類。 pickle
是Python
對象的序列化工具則比marshal
更通用些,它能夠兼容Python
的不一樣版本。json
是一種語言無關的數據結構,普遍用於各類網絡應用尤爲在REST API
的服務中的數據交互。