快速JSON编码器
项目描述
这是一个针对Python对象的超快速JSON编码器,适用于Python 3,旨在与各种Web浏览器中的原生JSON解码器兼容。
可以将数据编码为Python字符串(见 dumps)或字节序列(见 dumpb)。dumps() 返回的字符串保证只包含7位ASCII字符 [1],并且 dumps(obj).encode('ascii') = dumpb(obj)。
支持一个特殊的编码器类方法 encode_hook(obj),如果存在,则应用于输入对象,其余的处理应用于 encode_hook() 的输出。注意:encode_hook() 应始终返回一个对象;对于不应特别编码的对象,encode_hook() 应返回原始对象。
支持通过对象的方法 __mm_json__() 或 __mm_serialize__() 使用自定义编码器,如果可用。对于所有非本地类型,保证在尝试编码对象之前,先尝试 __mm_json__ 然后 __mm_serialize__。 [2]
原生支持字符串、整数、浮点数、True、False、None、列表、元组、字典、集合、frozensets、collections.OrderedDicts、collections.Set、collections.Sequence [3]、collections.Mapping、uuid.UUIDs [4]、decimal.Decimals、datetime.datetime 以及所有这些对象的派生对象。
对于无法以其他方式编码的对象,尝试使用 Encoder.default(obj) 方法将其转换为可编码对象。如果 Encoder.default 成功,则输出再次以任何其他对象的形式编码。
如果需要自定义处理原生支持的原始类型,存在一个 Encoder.encode_hook 方法。
示例
编码自定义对象
>>> from metamagic.json import dumps, dumpb >>> class Foo: ... def __mm_serialize__(self): ... return "Im foo" ... >>> dumps(Foo()) '"Im foo"' >>> dumps({Foo(): 123}) '{"Im foo":123}'
直接转换为字节
>>> dumpb(Foo()) b'"Im foo"'
绕过 JSON 缓冲区的序列化
>>> class JSONData: ... def __init__(self, data): ... self.data = data ... ... def __mm_json__(self): ... return self.data >>> a = JSONData('["abc", "def"]') >>> dumps([1,2,3,a]) '[1,2,3,["abc", "def"]]'
抛出异常
对于不支持的对象以及所有非字符串(或 UUIDs [5])的字典键,以及无法通过其 __mm_serialize__ 方法表示为字符串(或 UUIDs)的字典键,dumps() 和 dumpb() 都会抛出 TypeError。
default() 对于所有不支持的对象都会抛出 TypeError,并且重写的 default() 也应期望为它不支持的所有对象抛出 TypeError。
在编码整数时,如果整数值大于 JavaScript 支持的最大整数值(9007199254740992),则 dumps() 和 dumpb() 会抛出 ValueError(参见 http://ecma262-5.com/ELS5_HTML.htm#Section_8.5)。
在编码嵌套对象时,如果超过允许的嵌套级别(默认为 100,可以通过将所需值作为第二个参数传递给 dumps() 和 dumpb() 方法来重写),则会抛出 ValueError。
基准测试
Array with 256 short ascii strings: std json: 2.6581 sec, 11286 req/sec mm c json: 0.90321 sec, 33214 req/sec ( 2.9x ) mm c 1ini: 0.85578 sec, 35055 req/sec ( 3.1x ) mm c dumpb: 0.84517 sec, 35495 req/sec ( 3.1x ) marshal: 1.77567 sec, 16895 req/sec Array with 2048 3-char ascii strings: std json: 0.47259 sec, 4231 req/sec mm c json: 0.12481 sec, 16024 req/sec ( 3.8x ) mm c 1ini: 0.12261 sec, 16311 req/sec ( 3.9x ) mm c dumpb: 0.11732 sec, 17047 req/sec ( 4.0x ) marshal: 0.41334 sec, 4838 req/sec Array with 256 long ascii strings: std json: 1.30821 sec, 3822 req/sec mm c json: 0.47144 sec, 10605 req/sec ( 2.8x ) mm c 1ini: 0.44159 sec, 11322 req/sec ( 3.0x ) mm c dumpb: 0.4346 sec, 11504 req/sec ( 3.0x ) marshal: 0.85593 sec, 5841 req/sec Array with 256 long utf-8 strings: std json: 1.52419 sec, 1312 req/sec mm c json: 1.4438 sec, 1385 req/sec ( 1.1x ) mm c 1ini: 1.43666 sec, 1392 req/sec ( 1.1x ) mm c dumpb: 1.40142 sec, 1427 req/sec ( 1.1x ) marshal: 1.3413 sec, 1491 req/sec Medium complex object: std json: 3.5078 sec, 2850 req/sec mm c json: 1.45764 sec, 6860 req/sec ( 2.4x ) mm c 1ini: 1.43357 sec, 6975 req/sec ( 2.4x ) mm c dumpb: 1.47626 sec, 6773 req/sec ( 2.4x ) marshal: 1.04175 sec, 9599 req/sec Array with 256 doubles: std json: 3.37919 sec, 2959 req/sec mm c json: 2.23615 sec, 4471 req/sec ( 1.5x ) mm c 1ini: 2.48201 sec, 4028 req/sec ( 1.4x ) mm c dumpb: 2.23184 sec, 4480 req/sec ( 1.5x ) marshal: 0.14098 sec, 70932 req/sec Array with 256 ints: std json: 1.0185 sec, 19636 req/sec mm c json: 0.2752 sec, 72674 req/sec ( 3.7x ) mm c 1ini: 0.25349 sec, 78898 req/sec ( 4.0x ) mm c dumpb: 0.28252 sec, 70791 req/sec ( 3.6x ) marshal: 0.15442 sec, 129516 req/sec Array with 256 small ints: std json: 1.04397 sec, 191576 req/sec mm c json: 0.28152 sec, 710429 req/sec ( 3.7x ) mm c 1ini: 0.09222 sec, 2168726 req/sec ( 11.3x ) mm c dumpb: 0.27627 sec, 723929 req/sec ( 3.8x ) marshal: 0.08306 sec, 2407897 req/sec Array with 256 Decimals: std json: failed to serialize mm c json: 0.77161 sec, 10367 req/sec ( 0.0x ) mm c 1ini: 0.76022 sec, 10523 req/sec ( 0.0x ) mm c dumpb: 0.78671 sec, 10168 req/sec ( 0.0x ) marshal: failed to serialize Array with 256 True values: std json: 2.08432 sec, 38381 req/sec mm c json: 0.47159 sec, 169638 req/sec ( 4.4x ) mm c 1ini: 0.39814 sec, 200934 req/sec ( 5.2x ) mm c dumpb: 0.45191 sec, 177026 req/sec ( 4.6x ) marshal: 0.24776 sec, 322893 req/sec Array with 256 False values: std json: 2.0099 sec, 39802 req/sec mm c json: 0.50992 sec, 156887 req/sec ( 3.9x ) mm c 1ini: 0.43001 sec, 186042 req/sec ( 4.7x ) mm c dumpb: 0.50839 sec, 157359 req/sec ( 4.0x ) marshal: 0.25551 sec, 313099 req/sec Array with 256 dict{string, int} pairs: std json: 1.96227 sec, 4076 req/sec mm c json: 0.36569 sec, 21876 req/sec ( 5.4x ) mm c 1ini: 0.34565 sec, 23144 req/sec ( 5.7x ) mm c dumpb: 0.36583 sec, 21868 req/sec ( 5.4x ) marshal: 0.51862 sec, 15425 req/sec Array with 256 dict-based{string, int} pairs: std json: 4.20194 sec, 1903 req/sec mm c json: 3.74071 sec, 2138 req/sec ( 1.1x ) mm c 1ini: 3.70554 sec, 2158 req/sec ( 1.1x ) mm c dumpb: 3.77039 sec, 2121 req/sec ( 1.1x ) marshal: failed to serialize Array with 256 orderedDict{string, int} pairs: std json: 2.31765 sec, 431 req/sec mm c json: 0.70724 sec, 1413 req/sec ( 3.3x ) mm c 1ini: 0.69506 sec, 1438 req/sec ( 3.3x ) mm c dumpb: 0.70373 sec, 1420 req/sec ( 3.3x ) marshal: failed to serialize Dict with 256 arrays with 256 dict{string, int} pairs: std json: 3.78828 sec, 13 req/sec mm c json: 0.69496 sec, 71 req/sec ( 5.5x ) mm c 1ini: 0.69522 sec, 71 req/sec ( 5.4x ) mm c dumpb: 0.68382 sec, 73 req/sec ( 5.5x ) marshal: 1.02776 sec, 48 req/sec
测试
运行测试需要 pytest。