Python | JSON |
---|---|
dict | Object |
list, tuple | array |
str | string |
int, float, | numbers |
True | true |
False | false |
None | null |
你注意到了嗎? 還有很多python數(shù)據(jù)類型(set, datetime)不在上表中哦。
json模塊的dumps方法可以將python常用數(shù)據(jù)格式轉(zhuǎn)化為json格式。該方法還提供了很多可選參數(shù)如ident, separators, ensure_ascii, sort_keys和default參數(shù)。這些參數(shù)都非常有用,我們會稍后逐一介紹。
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格式數(shù)據(jù)外面都加了單引號,這說明dict類型數(shù)據(jù)已經(jīng)轉(zhuǎn)化成了json字符串。
>>> import json >>> json.dumps({"name":"John", "score": 112}) '{"name": "John", "score": 112}'
如果一個dict很長,生成的json字符串會非常長,這時我們可以設(shè)置indent參數(shù)使生成的json格式數(shù)據(jù)更優(yōu)美,更容易人們閱讀。代碼如下所示:
>>> import json >>> json.dumps({"name":"John", "score": 112}, indent=4) '{\n "name": "John",\n "score": 112\n}' >>> print(json.dumps({"name":"John", "score": 112}, indent=4)) { "name": "John", "score": 112 }
然而使用indent參數(shù)的代價是json字符串里增加了額外的空白,機器閱讀根本不需要它們,
即使不用indent參數(shù),你會發(fā)現(xiàn)dumps生成的json字符串中的','號和':'號分隔符后都會附加一個默認(rèn)空白字符,我們可以通過separators參數(shù)重新指定分隔符,從而去除無用的空白字符,如下所示。這樣可以減少無用數(shù)據(jù)的的傳輸,節(jié)省帶寬增加數(shù)據(jù)傳輸速度。
>>> import json >>> json.dumps({"name":"John", "score": 112}) '{"name": "John", "score": 112}' # 使用separators選項 >>> json.dumps({"name":"John", "score": 112}, separators=(',',':')) '{"name":"John","score":112}'
如果字符串有非ASCII字符(比如中文),它們在json序列化時都會被轉(zhuǎn)義成'\uXXXX'組成的ascii字符串。如果想得到更加易讀的字符串,可以設(shè)置ensure_ascii=False。
>>> import json >>> json.dumps({"Name":"小明", "Age": 16}) '{"Name": "\\u5c0f\\u660e", "Age": 16}' # 設(shè)置ensure_ascii=False >>> json.dumps({"Name":"小明", "Age": 16}, ensure_ascii=False) '{"Name": "小明", "Age": 16}'
一般的dict默認(rèn)是無序的,你還可以設(shè)置sort_keys = True對生成的json格式數(shù)據(jù)進(jìn)行排序,這里就不演示了。default參數(shù)我們后面會重點介紹。
與dumps方法不同,json模塊的dump方法用于將生成的json數(shù)據(jù)寫入磁盤文件。其用法和dumps類似,唯一不同的是需要指定需要寫入的文件,具體用法如下所示:
import json with open("json.txt", 'w') as f: json.dump({"Name":"小明", "Age": 16}, f, ensure_ascii=True)
json的loads方法用于將json格式數(shù)據(jù)轉(zhuǎn)化為python格式,實現(xiàn)數(shù)據(jù)的反序列化,如下所示。千萬別忘了在json符串外的單引號哦。
>>> import json >>> json.loads('{"Name": "小明", "Age": 16}') {'Name': '小明', 'Age': 16}
json的load方法與loads用法相似,不過它需要指定存有json數(shù)據(jù)的文件。
>>> import json >>> with open("json.txt", 'r') as f: json.load(f)
很多python數(shù)據(jù)類型(比如日期,集合和自定義的類)并不能直接被dumps方法序列化,這時會出現(xiàn) xxx is not JSON serializable的錯誤,如下面代碼所示。當(dāng)出現(xiàn)類似錯誤時,我們有兩種解決方案。
>>> import json >>> from datetime import datetime # DateTime類型 >>> json.dumps({"date":datetime.now()}) Traceback (most recent call last): TypeError: Object of type 'datetime' is not JSON serializable # 自定義的User類 >>> class User(object): def __init__(self, name): self.name = name >>> json.dumps(User("John")) Traceback (most recent call last): TypeError: Object of type 'User' is not JSON serializable
該方法的工作原理是先編寫數(shù)據(jù)類型轉(zhuǎn)化函數(shù),通過設(shè)置dumps方法里的default參數(shù)調(diào)用格式轉(zhuǎn)化函數(shù),將dumps方法不支持的數(shù)類型先轉(zhuǎn)化為字符串格式,再實現(xiàn)json序列化。
# 將datetime格式數(shù)據(jù)json化 >> > import json >> > from datetime import datetime >> > def date_to_str(obj): if isinstance(obj, datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, date): return obj.strftime('%Y-%m-%d') return TypeError >> > json.dumps({"date": datetime.now()}, default=date_to_str) '{"date": "2018-09-22 21:25:42"}' # 將set類型數(shù)據(jù)json化 >> > import json >> > set_data = {'my_set': {1, 2, 3}} >> > def set_to_list(obj): if isinstance(obj, set): return list(obj) raise TypeError >> > result = json.dumps(set_data, default=set_to_list)
對于我們自定義的類, 使用dumps方法時我們一般要先編寫obj_to_dict方法,將object轉(zhuǎn)化為字典dict再JSON序列化。同理,使用loads方法對json數(shù)據(jù)反序列化時,我們還需要編寫dict_to_obj方法,通過default參數(shù)調(diào)用。下面這2段代碼是比較通用的對象(object)與字典(dict)互轉(zhuǎn)的經(jīng)典代碼,請用微信收藏后再看。
# 將自定義的類轉(zhuǎn)化為字典,dumps方法使用 def obj_to_dict(obj): d = {} d['__class__'] = obj.__class__.__name__ d['__module__'] = obj.__module__ d.update(obj.__dict__) return d # 將字典轉(zhuǎn)化為自定義的類,loads方法使用 def dict_to_obj(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
另一個解決方案是繼承JSONEncoder類和JSONDecode類定義自己的編碼Encoder類,然后使用cls=MyEncoder,來調(diào)用編碼器。比如下例中我們定義了自己的DateTimeEncoder,將日期類型數(shù)據(jù)序列化。
from datetime import datetime, date import json class DateTimeEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime): return obj.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(obj, date): return obj.strftime('%Y-%m-%d') return json.JSONEncoder.default(self, obj) json_data = {'num': 1, 'date': datetime.now()} print(json.dumps(json_data, cls=DateTimeEncoder))
對于自定義的對象,我們也可以通過繼承JSONEncoder類實現(xiàn)它的序列化,如下所示:
import json class User(object): def __init__(self, name): self.name = name class MyJSONEncoder(json.JSONEncoder): def default(self, obj): d = {} d['__class__'] = obj.__class__.__name__ d['__module__'] = obj.__module__ d.update(obj.__dict__) return d user = User("John") json.dumps(user, cls=MyJSONEncoder))
對于簡單的數(shù)據(jù)序列化,方案一更容易理解,代碼也更少。但當(dāng)需要傳輸?shù)臄?shù)據(jù)很大時,使用繼承JSONEncoder類來實現(xiàn)序列化時有個很大的好處,就是可以通過iterencode()方法把一個很大的數(shù)據(jù)對象分多次進(jìn)行序列化,這對于網(wǎng)絡(luò)持續(xù)傳輸或?qū)懭氪蟮奈募浅S杏?。如下所示?/p>
>>> for chunk in MyJSONEncoder().iterencode(big_object): ... print(chunk)
Django編程就是是python編程,以上所介紹的序列化方法對django也是適用的。不同的是Django還有自己專屬的數(shù)據(jù)類型比如QuerySet和ValueQuerySet類型數(shù)據(jù),還提供了更便捷的serializers類。使用serializers類可以輕易將QuerySet格式的數(shù)據(jù)轉(zhuǎn)化為json格式。
# Django Queryset數(shù)據(jù) to Json from django.core import serializers data = serializers.serialize("json", SomeModel.objects.all()) data1 = serializers.serialize("json", SomeModel.objects.all(), fields=('name','id')) data2 = serializers.serialize("json", SomeModel.objects.filter(field = some_value))
有時候我們只需要查詢結(jié)果集的部分字段,可以使用values('字段名','字段名2')來要求返回的是哪些列的數(shù)據(jù).但是返回來的是ValuesQuerySet對象而不是QuerySet對象。ValuesQuerySet對象不能用 serializers.serialize() 方法序列化成json, 需要先轉(zhuǎn)換成list再用 json.dumps()方法序列化成json格式。示例代碼如下所示:
import json from django.core.serializers.json import DjangoJSONEncoder queryset = myModel.objects.filter(foo_icontains=bar).values('f1', 'f2', 'f3') data4 = json.dumps(list(queryset), cls=DjangoJSONEncoder)
如果你要利用django開發(fā)restful的web API, 為不同客戶端提供序列化過的json格式數(shù)據(jù),django-rest-framework才是你真正需要的序列化工具。與django自帶的serializers類相比,rest framework支持用戶驗證,查詢過濾和符合restful規(guī)范的url設(shè)計,我們后面會專門介紹。歡迎關(guān)注我的微信。
我們介紹了何為JSON序列化以及python json模塊的dumps, loads, dump和load方法。我們還介紹了如何將dumps方法不支持的數(shù)據(jù)格式(如日期,集合, 自定義的類和Django的QuerySet類型)如何通過要自定義格式轉(zhuǎn)化函數(shù)和繼承JsonEncoder類將它們轉(zhuǎn)化為json格式。希望本文對你有所幫助。喜歡的給個贊吧!
以上就是Python如何把不同類型數(shù)據(jù)的json序列化的詳細(xì)內(nèi)容,更多關(guān)于python 數(shù)據(jù)json序列化的資料請關(guān)注腳本之家其它相關(guān)文章!
標(biāo)簽:黃山 三沙 景德鎮(zhèn) 宿遷 濟南 臺灣 欽州 喀什
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Python如何把不同類型數(shù)據(jù)的json序列化》,本文關(guān)鍵詞 Python,如何,把,不,同類型,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。