orjsonを使ってみよう
orjsonモジュールについて
orjson は、Python用の高速なJSONライブラリです。標準のjsonライブラリや他のサードパーティライブラリよりも正確にシリアル化/非シリアル化することができます。 他にもdataclass、datetime、numpy、およびUUIDインスタンスをネイティブにシリアル化します。 次のような機能があります。
データクラスインスタンスを他のライブラリの40〜50倍の速度でシリアル化
datetime、date、timeインスタンスをRFC 3339形式にシリアル化 例:"1970-01-01T00:00:00+00:00"
numpy.ndarrayインスタンスを他のライブラリの0.3倍のメモリ使用量で4〜12倍の速度でシリアル化
標準ライブラリのjson と比較して、10倍から20倍の速さできれいに出力
str型ではなくbytes型にシリアル化されます。
標準ライブラリのjsonとは互換性がありません。
UnicodeをASCIIにエスケープせずにstrをシリアル化
"\\u597d" ではなく "好"
float型を他のライブラリの10倍の速度でシリアル化し、2倍の速度で逆シリアル化します。
str、int、list、およびdictのサブクラスをシリアル化し、他のサブクラスをシリアル化する方法をdefault引数で指定
デフォルトのフックを使用して任意のタイプをシリアル化します
厳密なUTF-8準拠であり、標準ライブラリよりも正確です
Nan / Infinity / -Infinityをサポートしないという点で厳密なJSON準拠
53ビット整数での厳密なJSON準拠のオプションがあり、64ビットがデフォルトでサポートされています
ファイルのようなオブジェクトからの読み取り/書き込みのためのload()やdump()関数は提供されていません。
orjson のインストール
orjson は次のようにインストールします。
code: bash
$ pip install orjson
orjsonの使用方法
code: orjson_demo.py
import numpy
import orjson, datetime, numpy
data = {
"type": "job",
"created_at": datetime.datetime(1970, 1, 1),
"status": "🆗 ",
"payload": numpy.array(1, 2], [3, 4),
}
sieiralized_data = orjson.dumps(data,
option=orjson.OPT_NAIVE_UTC | orjson.OPT_SERIALIZE_NUMPY)
new_data = orjson.loads(sieiralized_data)
print(new_data)
code: bash
% python orjson_demo.py
{'type': 'job', 'created_at': '1970-01-01T00:00:00+00:00', 'status': '🆗', 'payload': 1, 2], [3, 4}
シリアル化
dumps(
__obj: Any,
default: Optional[CallableAny], Any = ...,
option: Optionalint = ..., ) -> bytes: ...
dumps()はPythonオブジェクトをJSONにシリアル化します。
str、dict、list、tuple、int、float、bool、dataclasses.dataclass、typing.TypedDict、datetime.datetime、datetime.date、datetime.time、uuid.UUID、numpy.ndarray、Noneをネイティブにシリアル化します。default引数で任意のタイプをサポートします。 str、int、dict、list、dataclasses.dataclass、およびenum.Enumのサブクラスをシリアル化します。名前付きタプルオブジェクトを配列としてシリアル化することを避けるために、タプルのサブクラスをシリアル化しません。サブクラスのシリアル化を回避するには、オプションorjson.OPT_PASSTHROUGH_SUBCLASSを指定します。
出力は、UTF-8を含むbytesオブジェクトです。
Python のGILは、呼び出されている間が保持されます。
サポートされていないタイプでJSONEncodeErrorが発生します。この例外メッセージは、無効なオブジェクトを説明し、エラーメッセージ"Type is not JSON serializable: ...."を示します。これを修正するには、default引数で指定します。
無効なUTF-8を含むstrでJSONEncodeErrorが発生します。
デフォルトで64ビットを超える整数、またはOPT_STRICT_INTEGERの場合は53ビットを超える整数でJSONEncodeErrorを発生させます。
OPT_NON_STR_KEYSが指定されていない限り、dictにstr以外のタイプのキーがある場合、JSONEncodeErrorが発生します。
デフォルトの出力がデフォルトで254レベルを超える深さの処理に再帰する場合、JSONEncodeErrorが発生します。
循環参照でJSONEncodeErrorが発生します。
datetimeオブジェクトのtzinfoがサポートされていない場合、JSONEncodeErrorが発生します。
JSONEncodeErrorは、TypeErrorのサブクラスです。これは、標準ライブラリとの互換性のためです。
default引数
サブクラスまたは任意の型をシリアル化するには、サポートされている型を返す呼び出し可能オブジェクトとしてdefault引数を指定します。デフォルトは、関数、lambda、または呼び出し可能なクラスインスタンスです。タイプがdefault引数で処理されないことを指定するには、TypeErrorなどの例外を発生させます。
code: orjson_default.py
import orjson, decimal
def decimal_object(obj):
if isinstance(obj, decimal.Decimal):
return str(obj)
raise TypeError
try:
orjson.dumps(decimal.Decimal("0.0842389659712649442845"))
except orjson.JSONEncodeError as msg:
print(msg)
json_data = orjson.dumps(decimal.Decimal("0.0842389659712649442845"),
default=decimal_object)
try:
json_data = orjson.dumps({1, 2}, default=decimal_object)
except TypeError as msg:
print(msg)
code: bash
% python orjson_default.py
Type is not JSON serializable: decimal.Decimal
Type is not JSON serializable: set
default引数に与えた関数は、例外が発生する前にdefault引数で最大254回処理する必要があるオブジェクトを返す場合があります。
タイプを処理できない場合は、デフォルトで例外を発生させることが重要です。 それ以外の場合、Pythonは暗黙的にNoneを返します。これは、呼び出し元には正当な値のように見え、シリアル化されます。
option引数
option引数、データのシリアル化方法を変更するには、オプションを指定します。 各オプションは、orjsonの整数定数です。 複数のオプションを指定するには、それらを組み合わせてマスクします。
option=orjson.OPT_STRICT_INTEGER | orjson.OPT_NAIVE_UTC
標準ライブラリの json とは大きく使用方法が異なることに注意してください。
OPT_APPEND_NEWLINE
出力に'\n'追加します。 これは、dumps(...) + "\n" のパターンを同じですが、簡単になります。bytesオブジェクトは不変であり、このパターンは元のコンテンツをコピーします。
code: orjson_newline.py
import orjson
data = orjson.dumps([])
print(data)
data = orjson.dumps([], option=orjson.OPT_APPEND_NEWLINE)
print(data)
code: bash
$ python orjson_newline.py
b'[]'
b'[]\n'
OPT_INDENT_2
空白文字2つでインデントを使用した整形出力(プリティプリント)。 これは、標準ライブラリ json での indent=2 と同等です。 プリティプリントは遅く、出力は大きくなります。 orjsonは、プリティプリントでは最速のライブラリであり、標準ライブラリ json よりもプリティプリントでの速度低下がはるかに少なくなります。 このオプションは、他のすべてのオプションと互換性があります。
code: orjson_indent.py
import orjson
print('DATA:', repr(data))
normal = orjson.dumps(data)
indent_bytes = orjson.dumps(data, option=orjson.OPT_INDENT_2)
print('NORMAL:', normal)
print('INDENT bytes:', indent_bytes)
print('INDENT str:', indent_bytes.decode())
code: bash
% python orjson_indent.py
NORMAL: b'[{"a":"A","b":2,4,"c":3.0}]' INDENT bytes: b'[\n {\n "a": "A",\n "b": \n 2,\n 4\n ,\n "c": 3.0\n }\n]' INDENT str: [
{
"a": "A",
"b": [
2,
4
],
"c": 3.0
}
]
ここで、orjson ではシリアル化したデータはbytes型になることに注目してください。
OPT_NAIVE_UTC
tzinfoを使用せずにdatetime.datetimeオブジェクトをUTCとしてシリアル化します。 これは、tzinfoが設定されているdatetime.datetimeオブジェクトには影響しません。
code: orjson_native_utc.py
import orjson, datetime
date_obj = datetime.datetime(2021, 1, 1, 0, 0, 0),
json_data = orjson.dumps(date_obj)
print('NORMAL :', json_data)
json_data = orjson.dumps(date_obj, option=orjson.OPT_NAIVE_UTC)
print('NATIVE_UTC:', json_data)
code: bash
$ python orjson_native_utc.py
OPT_NON_STR_KEYS
標準ライブラリのjsonではデフォルトでstr、int、float、bool、またはNoneをシリアル化します。
orjson で optionにこのフラグがセットされると、str以外のタイプのdictキーをシリアル化します。 これにより、dictキーをstr、int、float、bool、None、datetime.datetime、datetime.date、datetime.time、enum.Enum、およびuuid.UUIDのいずれかにすることができます。 orjsonは、str以外のキーのシリアル化が他のライブラリよりも高速であるとベンチマークしています。 このオプションは、strキーの場合はデフォルトよりも遅くなります。
code: orjson_non_str_keys.py
import orjson, datetime, uuid
data = orjson.dumps(
{uuid.UUID("7202d115-7ff3-4c81-a7c1-2a1f067b1ece"): 1, 2, 3}, option=orjson.OPT_NON_STR_KEYS,
)
print(data)
data = orjson.dumps(
{datetime.datetime(2021, 1, 1, 0, 0, 0): 1, 2, 3}, option=orjson.OPT_NON_STR_KEYS | orjson.OPT_NAIVE_UTC,
)
print(data)
code: bash
$ python orjson_non_str_keys.py
b'{"7202d115-7ff3-4c81-a7c1-2a1f067b1ece":1,2,3}' b'{"2021-01-01T00:00:00+00:00":1,2,3}' datetime.datetime は RFC 3339 文字列であり、optionのフラグ設定に従います。 例外は、int型のシリアル化がOPT_STRICT_INTEGERに従わないことです。 このオプションフラグには、重複するキーが作成されるリスクがあります。 これは、非strオブジェクトが既存のキーと同じstrにシリアル化される可能性があるためです(例:{"1":true、1:false})。 dictに挿入される最後のキーは最後にシリアル化され、JSONの非シリアル化は最後に出現したキーを取得し(前の例ではfalse)、最初の値は失われます。
このオプションはorjson.OPT_SORT_KEYS と互換性があります。 並べ替えを使用する場合、並べ替えは不安定であり、重複するキーについては予測できないことに注意してください。
code: orjson_sort_keys.py
import orjson, datetime
data = orjson.dumps(
{ "other": 1,
datetime.date(2021, 1, 5): 2,
datetime.date(2021, 1, 3): 3
},
option=orjson.OPT_NON_STR_KEYS | orjson.OPT_SORT_KEYS
)
print(data)
code: bash
% python orjson_sort_keys.py
b'{"2021-01-03":3,"2021-01-05":2,"other":1}'
OPT_OMIT_MICROSECONDS
このオプションフラグは、datetime.datetimeインスタンスとdatetime.timeインスタンスのマイクロ秒フィールドをシリアル化しません。
code: orjson_omit_microseconds.py
import orjson, datetime
data = orjson.dumps(
datetime.datetime(2021, 1, 1, 0, 0, 0, 1),
)
print(data)
data = orjson.dumps(
datetime.datetime(2021, 1, 1, 0, 0, 0, 1),
option=orjson.OPT_OMIT_MICROSECONDS,
)
print(data)
code: bash
% python orjson_omit_microseconds.py
b'"2021-01-01T00:00:00.000001"'
b'"2021-01-01T00:00:00"'
OPT_PASSTHROUGH_DATACLASS
このオプションフラグは、dataclasses.dataclassインスタンスをdefault引数にそのまま渡します。 これにより、出力をカスタマイズできますが、速度は大幅に低下します。
code: orjson_passthrough_dataclass.py
import orjson, dataclasses
@dataclasses.dataclass
class User:
id: str
name: str
password: str
def user_object(obj):
if isinstance(obj, User):
return {"id": obj.id, "name": obj.name}
raise TypeError
data = orjson.dumps(User("3b1", "asd", "zxc"))
print(' DATA:', repr(data))
print('NORMAL:', data)
try:
data = orjson.dumps(User("3b1", "asd", "zxc"),
option=orjson.OPT_PASSTHROUGH_DATACLASS)
except TypeError as msg:
print('ERROR:', msg)
data = orjson.dumps(
User("3b1", "asd", "zxc"),
option=orjson.OPT_PASSTHROUGH_DATACLASS,
default=user_object,
)
print('CUSTOM:', data)
code: bash
% python orjson_passthrough_dataclass.py
DATA: b'{"id":"3b1","name":"asd","password":"zxc"}'
NORMAL: b'{"id":"3b1","name":"asd","password":"zxc"}'
ERROR: Type is not JSON serializable: User
CUSTOM: b'{"id":"3b1","name":"asd"}'
OPT_PASSTHROUGH_DATETIME
datetime.datetime、datetime.date、およびdatetime.timeインスタンスをdefault引数にそのまま渡します。 これにより、日時をカスタム形式(HTTP日付など)にシリアル化できます。
code: orjson_passthrough_datetime.py
import orjson, datetime
def custom_datetime(obj):
if isinstance(obj, datetime.datetime):
return obj.strftime("%a, %d %b %Y %H:%M:%S GMT")
raise TypeError
date_dict = {"created_at": datetime.datetime(2021, 1, 1)}
data = orjson.dumps(date_dict)
print(' DATA:', repr(data))
print('NORMAL:', data)
try:
data = orjson.dumps(
date_dict,
option=orjson.OPT_PASSTHROUGH_DATETIME
)
except TypeError as msg:
print('ERROR:', msg)
data = orjson.dumps(
date_dict,
option=orjson.OPT_PASSTHROUGH_DATETIME,
default=custom_datetime,
)
print('CUSTOM:', data)
code: bash
% python orjson_passthrough_datetime.py
DATA: b'{"created_at":"2021-01-01T00:00:00"}'
NORMAL: b'{"created_at":"2021-01-01T00:00:00"}'
ERROR: Type is not JSON serializable: datetime.datetime
CUSTOM: b'{"created_at":"Fri, 01 Jan 2021 00:00:00 GMT"}'
OPT_NON_STR_KEYSを使用している場合、これはdictキーの日時には影響しません。
OPT_PASSTHROUGH_SUBCLASS
組み込み型のサブクラスをdefault引数に渡します。
code: passthrough_subclass.py
import orjson
class Secret(str):
pass
def custom_type(obj):
if isinstance(obj, Secret):
return "******"
raise TypeError
sec_obj = Secret("zxc")
data = orjson.dumps(sec_obj)
print(' DATE:', data)
print('NORMAL:', data)
try:
data = orjson.dumps(
sec_obj,
option=orjson.OPT_PASSTHROUGH_SUBCLASS)
except TypeError as msg:
print('ERROR:', msg)
data = orjson.dumps(
sec_obj,
option=orjson.OPT_PASSTHROUGH_SUBCLASS,
default=custom_type)
print('CUSTOM:', data)
code: bash
$ python orjson_passthrough_subclass.py
DATE: b'"zxc"'
NORMAL: b'"zxc"'
ERROR: Type is not JSON serializable: Secret
CUSTOM: b'"******"'
OPT_NON_STR_KEYSを設定している場合、これはdictのキーとしてのサブクラスのシリアル化には影響しません。
OPT_SERIALIZE_DATACLASS
これは非推奨であり、バージョン3では効果がありません。バージョン2では、dataclasses.dataclassインスタンスをシリアル化するためにこれが必要でした。 詳細については、データクラスを参照してください。
OPT_SERIALIZE_NUMPY
numpy.ndarrayインスタンスをシリアル化します。
OPT_SERIALIZE_UUID
これは非推奨であり、バージョン3では効果がありません。バージョン2では、uuid.UUIDインスタンスをシリアル化するためにこれが必要でした。
OPT_SORT_KEYS
dictのキーをソートされた順序でシリアル化します。 デフォルトでは、不特定の順序でシリアル化されます。 これは、標準ライブラリ json のsort_keys=Trueと同等です。
これを使用して、ハッシュまたはテストの順序が一意んいなりますが、パフォーマンスが大幅に低下するため、一般的にはお勧めしません。
OPT_STRICT_INTEGER
整数に53ビットの制限を適用します。 それ以外の制限は64ビットで、Python標準ライブラリのjsonと同じです。
OPT_UTC_Z
datetime.datetimeインスタンスのUTCタイムゾーンを+00:00ではなくZとしてシリアル化します。
code: orjson_utc_z.py
import orjson, datetime
date_obj = datetime.datetime(2021, 1, 1, 0, 0, 0,
tzinfo=datetime.timezone.utc)
data = orjson.dumps(date_obj)
print(' DATA:', data)
print('NORMAL:', data)
data = orjson.dumps(
date_obj,
option=orjson.OPT_UTC_Z
)
print(' UTC_Z:', data)
code: bash
$ python orjson_utc_z.py
DATA: b'"2021-01-01T00:00:00+00:00"'
NORMAL: b'"2021-01-01T00:00:00+00:00"'
UTC_Z: b'"2021-01-01T00:00:00Z"'
非シリアル化
load()は、JSONをPythonオブジェクトに非シリアル化します。 dict、list、int、float、str、bool、Noneオブジェクトに逆シリアル化します。
bytes、bytearray、およびstrオブジェクトが入力として受け入れられます。 入力がbytes型として存在する場合は、bytesを渡すことをお勧めします。 これにより、メモリ使用量とレイテンシが低くなります。
入力は有効なUTF-8である必要があります。
orjsonは、プロセスの間、マップキーのキャッシュを維持します。 これにより、文字列の重複を回避することで、メモリ使用量を大幅に削減できます。 キーをキャッシュするには最大64バイトである必要があり、512エントリが保存されます。
GILは、呼び出しの間は保持されます。
無効なタイプまたは無効なJSONが指定された場合、JSONDecodeErrorが発生します。 これには、入力にNaN、Infinity、または-Infinityが含まれている場合が含まれます。これらは、標準ライブラリ jsonでは許されていますが、有効なJSONではありません。
JSONDecodeErrorは、json.JSONDecodeErrorとValueErrorのサブクラスです。 これは、標準ライブラリとの互換性のためです。
orjson での型
dataclass
orjsonは、dataclasses.dataclassのインスタンスをネイティブにシリアル化します。 インスタンスを他のライブラリの40〜50倍の速度でシリアル化し、dictのシリアル化と比較して他のライブラリで見られる深刻な速度低下を回避します。
__slots__を使用するデータクラス、フリーズされたデータクラス、オプションまたはデフォルトのアトリビュートを持つデータクラス、サブクラスなど、データクラスのすべてのバリアントを渡すことがサポートされています。 __slots__を使用しないことにはパフォーマンス上の利点があります。
データクラスはマップとしてシリアル化され、すべてのアトリビュートがシリアル化され、クラス定義で指定された順序になります。
code: orjson_type_dataclass.py
import dataclasses, orjson, typing
@dataclasses.dataclass
class Member:
id: int
active: bool = dataclasses.field(default=False)
@dataclasses.dataclass
class Object:
id: int
name: str
print(' DATA:', repr(data))
print('NORMAL:', data)
code: bash
$ python orjson_type_dataclass.py
ユーザーは、データクラスインスタンスのシリアル化方法を制御したい場合があります。たとえば、アトリビュートをシリアル化しない場合や、シリアル化時にアトリビュートの名前を変更する場合などです。 orjsonは、ユースケースが明確な場合、フィールドアトリビュートなどのメタデータマッピングを使用してサポートを実装する場合があります。
例:field(metadata={"json_serialize":False})
datetime
orjsonは、datetime.datetimeオブジェクトをRFC 3339 形式にシリアル化します。 例:例:"1970-01-01T00:00:00+00:00"
これはISO8601のサブセットであり、標準ライブラリのisoformat()と互換性があります。
code: orjson_type_datetime.py
import orjson, datetime
# Python 3.9 stdlib
try:
from zoneinfo import ZoneInfo as gettz
except:
from dateutil.tz import gettz
data = orjson.dumps(
datetime.datetime(2021, 12, 1, 2, 3, 4, 9,
tzinfo=gettz('Asia/Tokyo'))
)
print(' DATA:', repr(data))
print('NORMAL:', data)
data = orjson.dumps(
datetime.datetime.fromtimestamp(4123518902)
.replace(tzinfo=datetime.timezone.utc)
)
print(' DATA:', repr(data))
print('NORMAL:', data)
data = orjson.dumps(
datetime.datetime.fromtimestamp(4123518902)
)
print(' DATA:', repr(data))
print('NORMAL:', data)
code: bash
$ python orjson_type_datetime.py
DATA: b'"2021-12-01T02:03:04.000009+09:00"'
NORMAL: b'"2021-12-01T02:03:04.000009+09:00"'
DATA: b'"2100-09-02T06:55:02+00:00"'
NORMAL: b'"2100-09-02T06:55:02+00:00"'
DATA: b'"2100-09-02T06:55:02"'
NORMAL: b'"2100-09-02T06:55:02"'
datetime.datetimeは、tzinfoがNone、datetime.timezone.utc、Python3.9以降では標準ライブラリ zoneinfo のタイムゾーンインスタンス、またはサードパーティのpendulium、pytz、dateutilライブラリのタイムゾーンインスタンスを持つインスタンスをサポートします。
datetime.timeオブジェクトにtzinfoを含めることはできません。
datetime.dateオブジェクトは常にシリアル化されます。
code: orjson_type_datetime2.py
import orjson, datetime
data = orjson.dumps(datetime.time(12, 0, 15, 290))
print(' TIME:', data)
data = orjson.dumps(datetime.date(2021, 1, 2))
print(' DATE:', data)
code: bash
% python orjson_type_datetime2.py
TIME: b'"12:00:15.000290"'
DATE: b'"2021-01-02"'
tzinfoでエラーが発生すると、JSONEncodeErrorが発生します。
dumps()を呼び出す前に実行するよりも、orjsonにdatetimeオブジェクトをシリアル化させる方が高速です。 pendulum.datetimeなどのサポートされていないタイプを使用する場合は、default引数を使用します。
datetimeオブジェクトのシリアル化を無効にするには、オプションorjson.OPT_PASSTHROUGH_DATETIMEを指定します。
enum
orjsonはenum型をネイティブにシリアル化します。 オプションはそれらの値に適用されます。
code: orjson_type_enum.py
import enum, datetime, orjson
class DatetimeEnum(enum.Enum):
EPOCH = datetime.datetime(2021, 1, 1, 0, 0, 0)
data = orjson.dumps(DatetimeEnum.EPOCH)
print('NORMAL:', data)
data = orjson.dumps(DatetimeEnum.EPOCH, option=orjson.OPT_NAIVE_UTC)
print(' UTC:', data)
code: bash
python orjson_type_enum.py
NORMAL: b'"2021-01-01T00:00:00"'
UTC: b'"2021-01-01T00:00:00+00:00"'
サポートされていないタイプのメンバーを持つ列挙型は、default引数を使用してシリアル化できます。
code: orjson_type_enum_default.py
import enum, orjson
class Custom:
def __init__(self, val):
self.val = val
def custom_obj(obj):
if isinstance(obj, Custom):
return obj.val
raise TypeError
class CustomEnum(enum.Enum):
ONE = Custom(1)
data = orjson.dumps(CustomEnum.ONE, default=custom_obj)
print(data)
code: bash
% python orjson_type_enum_default.py
b'1'
float
orjsonは、精度と丸めによる欠損すること、倍精度浮動小数点数をシリアル化および逆シリアル化します。 同じ動作が、ujson、jsonで観察されます。 ujson 1.35は、シリアル化と逆シリアル化の両方で不正確でした。つまり、データが変更され、最近の2.0リリースは正確です。
orjson.dumps()は、JSONに準拠していないNan、Infinity、および-Infinityをnullとしてシリアル化します。
code: orjson_type_float.py
import orjson, ujson, json
print('orjson:', data)
print('ujson:', data)
print('json:', data)
code: bash
$ python orjson_type_float.py
int
orjsonは、デフォルトで64ビット整数をシリアル化および逆シリアル化します。 サポートされる範囲は、符号付き64ビット整数の最小値(-9223372036854775807)から符号なし64ビット整数の最大値(18446744073709551615)です。 これは広く互換性がありますが、整数の53ビットのみをサポートする実装があります(例:Webブラウザ)。 これらの実装では、53ビットの範囲を超える値でJSONEncodeErrorを発生させるようにdumps()を構成できます。
code: orjson_type_int.py
import orjson
data = orjson.dumps(9007199254740992)
print(data)
try:
data = orjson.dumps(9007199254740992,
option=orjson.OPT_STRICT_INTEGER)
except orjson.JSONEncodeError as msg:
print('JSONEncodeError:', msg)
try:
data = orjson.dumps(-9007199254740992,
option=orjson.OPT_STRICT_INTEGER)
except orjson.JSONEncodeError as msg:
print('JSONEncodeError:', msg)
code: bash
$ python orjson_type_int.py
b'9007199254740992'
JSONEncodeError: Integer exceeds 53-bit range
JSONEncodeError: Integer exceeds 53-bit range
numpy
orjsonは、numpy.ndarrayおよび個々のnumpy.float64、numpy.float32、numpy.int64、numpy.int32、numpy.int8、numpy.uint64、numpy.uint32、およびnumpy.uint8インスタンスをネイティブにシリアル化します。 配列のdtypeは、numpy.bool、numpy.float32、numpy.float64、numpy.int32、numpy.int64、numpy.uint32、numpy.uint64、numpy.uintp、またはnumpy.intpの場合があります。 orjsonは、numpyインスタンスのシリアル化において、比較されたすべてJSONシリアライザーライブラリよりも高速です。 numpyデータをシリアル化するには、option=orjson.OPT_SERIALIZE_NUMPY を指定する必要があります。
code: orjson_type_numpy.py
import orjson, numpy
data = orjson.dumps(
numpy.array(1, 2, 3], [4, 5, 6),
option=orjson.OPT_SERIALIZE_NUMPY,
)
print(data)
code: bash
$ python orjson_type_numpy.py
b'1,2,3],[4,5,6'
配列は、連続するC配列(C_CONTIGUOUS)であり、サポートされているデータ型の1つである必要があります。
配列が連続したC配列ではない場合、またはサポートされているデータ型が含まれている場合、orjsonはdefaultに渡します。defaultには、obj.tolist()を指定できます。 予期しない配列の形式が正しくない場合、orjson.JSONEncodeErrorが発生します。
orjsonには、numpyに対するインストールまたはコンパイルの依存関係はありません。 実装は独立しており、PyArrayInterfaceを使用してnumpy.ndarrayを読み取ります。
str
orjsonは、厳格にUTF-8への準拠しています。これは、無効なUTF-8であるUTF-16サロゲート(Surrogates)をシリアル化および逆シリアル化する標準ライブラリのjsonモジュールよりも厳密です。例:\ud800など。
orjson.dumps()に有効なUTF-8を含まないstrが指定された場合、orjson.JSONEncodeErrorが発生します。 load()が無効なUTF-8が受け取ると、orjson.JSONDecodeErrorが発生します。
orjsonは、不正な入力で一貫してエラーが発生するJSONライブラリです。
これは、正しい挙動です。
code: orjson_type_str.py
import orjson, ujson, json
try:
data = orjson.dumps('\ud800')
except orjson.JSONEncodeError as msg:
print('orjson JSONEncodeError:', msg)
try:
data = ujson.dumps('\ud800')
except UnicodeEncodeError as msg:
print('ujson UnicodeEncodeError:', msg)
data = json.dumps('\ud800')
print('json dumps():', data)
try:
data = orjson.loads('"\\ud800"')
except orjson.JSONDecodeError as msg:
print('orjson JSONDecodeError:', msg)
data = ujson.loads('"\\ud800"')
print('ujson loads():{!r}'.format(data))
data = json.loads('"\\ud800"')
print('json loads():{!r}'.format(data))
code: bash
$ python orjson_type_str.py
orjson JSONEncodeError: str is not valid UTF-8: surrogates not allowed
ujson UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 0: surrogates not allowed
json dumps(): "\ud800"
orjson JSONDecodeError: unexpected end of hex escape at line 1 column 8: line 1 column 1 (char 0)
ujson loads():''
json loads():'\ud800'
不正な入力の非シリアル化に最善を尽くすには、最初に入力データをreplaceまたはlossy引数を使用してbytes型をデコードします。
code: orjson_type_str_errors.py
import orjson
try:
data = orjson.loads(b'"\xed\xa0\x80"')
except orjson.JSONDecodeError as msg:
print('JSONDecodeError:', msg)
data = orjson.loads(b'"\xed\xa0\x80"'.decode("utf-8", "replace"))
print('decoded:', data)
code: bash
% python orjson_type_str_errors.py
JSONDecodeError: str is not valid UTF-8: surrogates not allowed: line 1 column 1 (char 0)
decoded: ���
uuid
orjsonは、uuid.UUIDインスタンスをRFC 4122形式にシリアル化します。 例:f81d4fae-7dec-11d0-a765-00a0c91e6bf6など
code: orjson_type_uuid.py
import orjson, uuid
data = orjson.dumps(uuid.UUID('f81d4fae-7dec-11d0-a765-00a0c91e6bf6'))
print(data)
data = orjson.dumps(uuid.uuid5(uuid.NAMESPACE_DNS, "python.org"))
print(data)
code: bash
$ python orjson_type_uuid.py
b'"f81d4fae-7dec-11d0-a765-00a0c91e6bf6"'
b'"886313e1-3b8a-5372-9b90-0c9aee199e5d"'
まとめ
orjson は、Python 標準ライブラリのjson とは互換性がないものの、使用メモリが少ない高速なJSONのシリアル化/非シリアル化を処理することができます。
参考
Python 公式ドキュメント