覺得我們的內容實用嗎?MyApollo 電子報讀者募集中!歡迎訂閱電子報!
orjson 是一套由 Rust 實作的 Python 套件,專門用以處理 JSON 相關的 encode 與 decode 的工作,效率不僅快(根據官方測試最快可以達到 json 模組的 40 到 50 倍效率)更天生能直接處理 Python 內建 json 模組所無法序列化(serialize)的 datetime, UUID, dataclass 等資料,不需額外編寫序列化的處理程式。
如果你想改善 Python API server 處理 JSON 的速度,以降低系統回應時間,又或者你有大量 JSON 相關的資料要處理,想有效減少處理時間的話,不妨試試 orjson 吧!
前言#
Python 雖然有內建 json 模組供開發者處理 JSON 格式的資料,例如將資料輸出為 JSON 格式,或將 JSON 字串載入並轉為 Python 資料。
不過 Python 內建的 json 模組效率卻不夠好之外,使用上也容易因為遇到 dataclass, datetime, UUID 等無法序列化(serialize)的資料,而造成 TypeError , 因此在輸出 JSON 格式的字串時,都需要針對 set, datetime 或 UUID 等型別的資料先轉換成 int, float 或 str 等型態,才能正確輸出 JSON 格式的字串,詳細問題與做法可以參考 製作 JSON serializable 的類別 一文。
也許小型的應用(application)感覺不出差異,一旦應用長大到每秒要處理相當多的 JSON 資料時,勢必要使用更快、更方便的 JSON 模組以加速應用處理 JSON 的速度。
本文所介紹的 orjson 就是解決上述執行效率與 JSON 序列化問題的最佳解決方案——快又方便有效。
本文環境#
- Python 3
- Google Colab
- orjson
$ pip install orjson
內建 json 模組 vs. orjson#
首先下列一段簡單的程式碼,就能讓內建的 json 模組出錯:
import json
from datetime import datetime
d = {
'time': datetime.now(),
}
j = json.dumps(d)
執行結果如下,可以看到內建 json 模組無法處理 datatime 型態的資料,因此拋出 TypeError: Object of type datetime is not JSON serializable 的例外錯誤(exception):

但是 orjson 天生就能夠處理 datetime, date 等型態的資料,因此不會發生問題,例如:
import orjson
from datetime import datetime
d = {
'time': datetime.now(),
}
j = orjson.dumps(d)
print(j)
上述執行結果如下,可以看到 orjson 能夠正常處理 datetime 型態的資料:
b'{"time":"2023-05-10T02:36:43.813289"}'
值得注意的是, orjson 所輸出的 JSON 格式是 bytes, 所以如果要轉為 Python string 需要呼叫 decode() 方法,例如:
orjson.dumps({'time': datetime.now()}).decode()
不過輸出 bytes 的好處是寫檔效率較好,可以將 open() 函式的 mode 參數設定為 binary mode, 例如 wb 直接將 bytes 寫入檔案(因為 Python 不需再額外呼叫 deocde 所以速度較快):
with open('output.jsonlines', 'wb') as file:
file.write(orjson.dumps(d, option=orjson.OPT_APPEND_NEWLINE)
如果不想輸出 datetime 的 microseconds, 可以設定 orjson 的 option 參數為 orjson.OPT_OMIT_MICROSECONDS , 例如:
import orjson
from datetime import datetime
j = orjson.dumps(datetime.now(), option=orjson.OPT_OMIT_MICROSECONDS)
print(j)
上述執行結果如下,可以看到 orjson 只輸出到秒為止, microseconds 的部分被拿掉了:
b'"2023-05-10T05:51:31"'
orjson 也能正常處理含有時區(tzinfo)的 datetime 資料, 例如:
import orjson, datetime, zoneinfo
orjson.dumps(
datetime.datetime(
2023, 5, 1, 2, 3, 4, 5,
tzinfo=zoneinfo.ZoneInfo('Asia/Taipei'),
)
)
上述執行結果如下,可以看到結果中有 +08:00 時區的資訊:
b'"2022-12-01T02:03:04.000009+08:00"'
orjson 內建多種原本 Python json 模組無法處理的資料,例如:
此外,速度的部分我們也可以用 1 個簡單的 dict 型態的資料進行比較:
target = {
"message": "Hello, JSON",
"count": 10,
}
以下使用 %time 指令比較 json 與 orjson 的速度:
%time json.dumps(target)
%time orjson.dumps(target)
可以看到 orjson 至少快 json 模組至少 1 倍( 24 µs vs. 10 µs ):

不過這僅是我們所做的粗淺比較,詳細的 benchmark 可以參考 orjson 所提供的比較數據。
dataclass#
另一個 orjson 吸引人的功能特點是 orjson 支援處理 dataclass 的 JSON 序列化(serialization),這也是內建 json 模組所無法處理的,例如下列範例:
import json
from dataclasses import dataclass
@dataclass
class User(object):
uid: int
name: str
role: str
user = User(1, "root", "admin")
json.dumps(user)
上述範例在試圖將 User dataclass 輸出為 JSON 時,出現 TypeError 的例外錯誤,如下圖:

不過 orjson 能夠正確處理 dataclass:
import orjson
from dataclasses import dataclass
@dataclass
class User(object):
uid: int
name: str
role: str
user = User(1, "root", "admin")
orjson.dumps(user)
上述執行結果如下,可以看到 User dataclass 已經被正確序列化:

numpy#
numpy 的 JSON 序列化也是 orjson 所主打的功能特點,不過 orjson 預設並沒有開啟 numpy 序列化的功能,如下列範例會出現 TypeError :
import orjson, numpy
orjson.dumps(
numpy.array([[1, 2, 3], [4, 5, 6]]),
)

如果要開啟 numpy 序列化功能,需要設定 orjson 的 option 參數 orjson.OPT_SERIALIZE_NUMPY , 例如:
import orjson, numpy
orjson.dumps(
numpy.array([[1, 2, 3], [4, 5, 6]]),
option=orjson.OPT_SERIALIZE_NUMPY,
)
orjson.loads() 載入 JSON 資料#
如果想載入 JSON 字串,可以呼叫 orjson.loads(), 該函式支援傳入 string 與 bytes:
傳入 string:
orjson.loads('{"uid":1,"name":"root","role":"admin"}')
傳入 bytes:
orjson.loads(b'{"uid":1,"name":"root","role":"admin"}')
因此如果是從檔案中讀取出來,也不用額外轉成字串處理,可以直接用 mode='rb' 讀檔案:
with open('input.jsonlines', 'rb') as file:
for line in file:
orjson.loads(line)
default 參數#
雖然 orjosn 已經支援多種資料型態的序列化,但也是有無法序列化的資料型態,例如 decimal 就無法被序列化為 JSON, 因此導致 TypeError 發生:
import orjson, decimal
orjson.dumps(decimal.Decimal("0.123"))

這種情況下,可以設定 default 參數,如果是 orjson 無法序列化的資料,將會傳給 default 函式進行處理,如下列範例中的 default 函式,該函式會判斷傳進來的資料是否為 decimal, 如果是則轉為字串,若不是則拋出 TypeError , 如果要處理更多不同的資料,擴充 default 函式即可:
import orjson, decimal
def default(obj):
if isinstance(obj, decimal.Decimal):
return str(obj)
raise TypeError
orjson.dumps(decimal.Decimal("0.123"), default=default)

更多相關做法可以參閱 製作 JSON serializable 的類別 一文。
總結#
orjson 憑藉著 Rust 實作的效能優勢以及支援各種常見的資料型態序列化,不僅能夠減少 Python 開發者的負擔,也能有效提升 JSON 相關應用執行速度。
值得一提的是 orjson 並不提供 load() 與 dump() 2 個方法,如果你的 JSON 應用沒有用到 json.load() 與 json.dump() 2 個函式(少個 s ),只要使用以下 import 方式就可以無痛轉為使用 orjson:
import orjson as json
如果你在尋找一種方法能夠簡單無痛提升 JSON 相關應用的效能,不仿考慮使用 orjson 吧,肯定能夠帶來一些幫助!
References#
GitHub - ijl/orjson: Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy