Python - 製作 JSON serializable 的類別
Posted on Mar 29, 2018 in Python 程式設計 - 中階 by Amo Chen ‐ 2 min read
Python 的 json
模組十分方便,可以把 dict()
tuple()
list()
str()
int()
等資料型別轉成 JSON 字串,不過遇到像是 set()
時,就會產生以下錯誤:
>>> import json
>>> json.dumps(set())
...(略)...
TypeError: Object of type 'set' is not JSON serializable
原因在於 json.dumps()
中預設並沒有處理 set()
等型別的序列化( serialization )。
雖然如此, json.dumps()
還是有參數能夠處理這些無法被序列化的類別(class)或型別。
json.dumps()
有個參數 cls
可以代入 1 個可以幫忙轉換資料為 JSON serializable 的 class ,該類別只需繼承 json.JSONEncoder
並實作 default
方法,在該方法中實作轉換資料的功能。
p.s. 如果是使用 Django 的話,可以用 DjangoJSONEncoder 取代 json.JSONEncoder
以下為可以轉換 set
為 JSON serializable 的 list
的範例類別:
import json
class AdvancedJSONEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
print(json.dumps(set(['foo', 'bar']), cls=AdvancedJSONEncoder))
執行結果:
["foo", "bar"]
可以看到 TypeError
已經消失,因為 set()
是 JSON Serializable 了。
基於這個方法,我們可以更進一步在每個自訂的類別實作一些特殊的方法,讓自訂的類別成為 JSON serializable 的類別。
例如以下自訂的類別 User 在 json.dumps()
會出現錯誤:
import json
class User(object):
def __init__(self, username):
self.username = username
user = User('foo')
json.dumps(user)
執行時產生的錯誤:
TypeError: Object of type 'User' is not JSON serializable
為了讓 User 類別成為 JSON serializable ,可以改寫成為:
import json
class User(object):
def __init__(self, username):
self.username = username
def __jsonencode__(self):
return {'username': self.username}
class AdvancedJSONEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, '__jsonencode__'):
return obj.__jsonencode__()
if isinstance(obj, set):
return list(obj)
return json.JSONEncoder.default(self, obj)
user = User('foo')
print(json.dumps(user, cls=AdvancedJSONEncoder))
執行結果:
{"username": "foo"}
上述範例可以看到我們改寫 AdvancedJSONEncoder
類別,並在裡面加以下的程式,判斷只要 obj 含有 __jsonencode__
屬性,就直接呼叫並回傳它。
if hasattr(obj, '__jsonencode__'):
return obj.__jsonencode__()
因此只要在任意類別中實作 __jsonencode__
方法,並在裡面回傳 JSON serializable 的資料即可讓一個自訂類別成為 JSON serializable 的類別,這也就是為什麼我們在 User.__jsonencode__
選擇回傳 dict()
型別的資料,因為它是 JSON serializable 的資料型別。
以上就是關於製作 JSON serializable 的類別的介紹。
Happy coding!
References
https://docs.python.org/3/library/json.html#json.dump
https://docs.djangoproject.com/en/2.0/topics/serialization/