orjson es una biblioteca JSON rápida y correcta para Python. Se compara como la biblioteca Python más rápida para JSON y es más correcta que la biblioteca json estándar u otras bibliotecas de terceros. Serializa instancias de clase de datos, fecha y hora, numpy y UUID de forma nativa.
orjson.dumps() es aproximadamente 10 veces más rápido que json
, serializa tipos y subtipos comunes, tiene un parámetro default
para que la persona que llama especifique cómo serializar tipos arbitrarios y tiene una serie de indicadores que controlan la salida.
orjson.loads() es aproximadamente 2 veces más rápido que json
y cumple estrictamente con UTF-8 y RFC 8259 ("El formato de intercambio de datos de notación de objetos JavaScript (JSON)").
La biblioteca no proporciona lectura y escritura en archivos, archivos JSON delimitados por líneas, etc.
orjson admite CPython 3.8, 3.9, 3.10, 3.11, 3.12, 3.13 y 3.14.
Distribuye ruedas amd64/x86_64, i686/x86, aarch64/armv8, arm7, POWER/ppc64le y s390x para Linux, ruedas amd64 y aarch64 para macOS y ruedas amd64 e i686/x86 para Windows.
orjson no admite ni admitirá PyPy, compilaciones integradas de Python para Android/iOS ni subintérpretes PEP 554.
Los lanzamientos siguen el control de versiones semántico y la serialización de un nuevo tipo de objeto sin un indicador de suscripción se considera un cambio importante.
orjson tiene licencia de Apache 2.0 y MIT. El repositorio y el rastreador de problemas es github.com/ijl/orjson, y allí se pueden enviar parches. Hay un CHANGELOG disponible en el repositorio.
Para instalar una rueda desde PyPI, instale el paquete orjson
.
En formato requirements.in
o requirements.txt
, especifique:
orjson >= 3.10,<4
En formato pyproject.toml
, especifique:
orjson = " ^3.10 "
Para construir una rueda, ver embalaje.
Este es un ejemplo de serialización, con opciones especificadas, y deserialización:
> >> import orjson , datetime , numpy
> >> data = {
"type" : "job" ,
"created_at" : datetime . datetime ( 1970 , 1 , 1 ),
"status" : "?" ,
"payload" : numpy . array ([[ 1 , 2 ], [ 3 , 4 ]]),
}
> >> orjson . dumps ( data , option = orjson . OPT_NAIVE_UTC | orjson . OPT_SERIALIZE_NUMPY )
b'{"type":"job","created_at":"1970-01-01T00:00:00+00:00","status":" xf0 x9f x86 x97 ","payload":[[1,2],[3,4]]}'
> >> orjson . loads ( _ )
{ 'type' : 'job' , 'created_at' : '1970-01-01T00:00:00+00:00' , 'status' : '?' , 'payload' : [[ 1 , 2 ], [ 3 , 4 ]]}
La versión 3 de orjson serializa más tipos que la versión 2. Las subclases de str
, int
, dict
y list
ahora están serializadas. Esto es más rápido y más similar a la biblioteca estándar. Se puede desactivar con orjson.OPT_PASSTHROUGH_SUBCLASS
. Las instancias dataclasses.dataclass
ahora se serializan de forma predeterminada y no se pueden personalizar en una función default
a menos que se especifique option=orjson.OPT_PASSTHROUGH_DATACLASS
. Las instancias uuid.UUID
se serializan de forma predeterminada. Para cualquier tipo que ahora esté serializado, las implementaciones en una función default
y las opciones que las habilitan se pueden eliminar, pero no es necesario. No hubo cambios en la deserialización.
Para migrar desde la biblioteca estándar, la mayor diferencia es que orjson.dumps
devuelve bytes
y json.dumps
devuelve un str
.
Los usuarios con objetos dict
que utilizan claves que no son str
deben especificar option=orjson.OPT_NON_STR_KEYS
.
sort_keys
se reemplaza por option=orjson.OPT_SORT_KEYS
.
indent
se reemplaza por option=orjson.OPT_INDENT_2
y no se admiten otros niveles de sangría.
ensure_ascii
probablemente no sea relevante hoy y los caracteres UTF-8 no se pueden pasar a ASCII.
def dumps (
__obj : Any ,
default : Optional [ Callable [[ Any ], Any ]] = ...,
option : Optional [ int ] = ...,
) -> bytes : ...
dumps()
serializa objetos Python a JSON.
Serializa de forma nativa str
, dict
, list
, tuple
, int
, float
, bool
, None
, dataclasses.dataclass
, typing.TypedDict
, datetime.datetime
, datetime.date
, datetime.time
, uuid.UUID
, numpy.ndarray
y orjson.Fragment
Instancias orjson.Fragment
. Admite tipos arbitrarios de forma default
. Serializa subclases de str
, int
, dict
, list
, dataclasses.dataclass
y enum.Enum
. No serializa subclases de tuple
para evitar serializar objetos namedtuple
como matrices. Para evitar la serialización de subclases, especifique la opción orjson.OPT_PASSTHROUGH_SUBCLASS
.
La salida es un objeto bytes
que contiene UTF-8.
El bloqueo global del intérprete (GIL) se mantiene mientras dure la llamada.
Genera JSONEncodeError
en un tipo no compatible. Este mensaje de excepción describe el objeto no válido con el mensaje de error Type is not JSON serializable: ...
Para solucionar este problema, especifique el valor predeterminado.
Genera JSONEncodeError
en una str
que contiene UTF-8 no válido.
Genera JSONEncodeError
en un número entero que excede los 64 bits de forma predeterminada o, con OPT_STRICT_INTEGER
, 53 bits.
Genera JSONEncodeError
si un dict
tiene una clave de un tipo distinto de str
, a menos que se especifique OPT_NON_STR_KEYS
.
Genera JSONEncodeError
si la salida default
recurre al manejo default
de más de 254 niveles de profundidad.
Genera JSONEncodeError
en referencias circulares.
Genera JSONEncodeError
si no se admite un tzinfo
en un objeto de fecha y hora.
JSONEncodeError
es una subclase de TypeError
. Esto es por compatibilidad con la biblioteca estándar.
Si el error fue causado por una excepción default
, JSONEncodeError
encadena la excepción original como __cause__
.
Para serializar una subclase o tipos arbitrarios, especifique default
como un invocable que devuelve un tipo admitido. default
puede ser una función, lambda o una instancia de clase invocable. Para especificar que un tipo no se manejó de default
, genere una excepción como TypeError
.
> >> import orjson , decimal
> >>
def default ( obj ):
if isinstance ( obj , decimal . Decimal ):
return str ( obj )
raise TypeError
> >> orjson . dumps ( decimal . Decimal ( "0.0842389659712649442845" ))
JSONEncodeError : Type is not JSON serializable : decimal . Decimal
> >> orjson . dumps ( decimal . Decimal ( "0.0842389659712649442845" ), default = default )
b'"0.0842389659712649442845"'
> >> orjson . dumps ({ 1 , 2 }, default = default )
orjson . JSONEncodeError : Type is not JSON serializable : set
El invocable default
puede devolver un objeto que a su vez debe manejarse de forma default
hasta 254 veces antes de que se genere una excepción.
Es importante que default
genere una excepción si no se puede manejar un tipo. De lo contrario, Python devuelve implícitamente None
, que a la persona que llama le parece un valor legítimo y está serializado:
> >> import orjson , json
> >>
def default ( obj ):
if isinstance ( obj , decimal . Decimal ):
return str ( obj )
> >> orjson . dumps ({ "set" :{ 1 , 2 }}, default = default )
b'{"set":null}'
> >> json . dumps ({ "set" :{ 1 , 2 }}, default = default )
'{"set":null}'
Para modificar cómo se serializan los datos, especifique option
. Cada option
es una constante entera en orjson
. Para especificar varias opciones, enmascarelas juntas, por ejemplo, option=orjson.OPT_STRICT_INTEGER | orjson.OPT_NAIVE_UTC
.
Agregue n
a la salida. Esto es una conveniencia y optimización para el patrón de dumps(...) + "n"
. Los objetos bytes
son inmutables y este patrón copia el contenido original.
> >> import orjson
> >> orjson . dumps ([])
b"[]"
> >> orjson . dumps ([], option = orjson . OPT_APPEND_NEWLINE )
b"[] n "
Impresión bonita con una sangría de dos espacios. Esto equivale a indent=2
en la biblioteca estándar. La impresión bonita es más lenta y el resultado es mayor. orjson es la biblioteca comparada más rápida en impresión bonita y tiene una desaceleración mucho menor para la impresión bonita que la biblioteca estándar. Esta opción es compatible con todas las demás opciones.
> >> import orjson
> >> orjson . dumps ({ "a" : "b" , "c" : { "d" : True }, "e" : [ 1 , 2 ]})
b'{"a":"b","c":{"d":true},"e":[1,2]}'
> >> orjson . dumps (
{ "a" : "b" , "c" : { "d" : True }, "e" : [ 1 , 2 ]},
option = orjson . OPT_INDENT_2
)
b'{ n "a": "b", n "c": { n "d": true n }, n "e": [ n 1, n 2 n ] n }'
Si se muestran, la sangría y los saltos de línea aparecen así:
{
"a" : " b " ,
"c" : {
"d" : true
},
"e" : [
1 ,
2
]
}
Esto mide la serialización del dispositivo github.json como compacto (52 KB) o bonito (64 KB):
Biblioteca | compacto (ms) | bonita (sra.) | contra orjson |
---|---|---|---|
orjson | 0,01 | 0,02 | 1 |
json | 0,13 | 0,54 | 34 |
Esto mide la serialización del dispositivo citm_catalog.json, que es el peor de los casos debido a la cantidad de anidamiento y nuevas líneas, como compacto (489 KB) o bonito (1,1 MiB):
Biblioteca | compacto (ms) | bonita (sra.) | contra orjson |
---|---|---|---|
orjson | 0,25 | 0,45 | 1 |
json | 3.01 | 24.42 | 54.4 |
Esto se puede reproducir usando el script pyindent
.
Serializar objetos datetime.datetime
sin tzinfo
como UTC. Esto no tiene ningún efecto en los objetos datetime.datetime
que tienen tzinfo
configurado.
> >> import orjson , datetime
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ),
)
b'"1970-01-01T00:00:00"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ),
option = orjson . OPT_NAIVE_UTC ,
)
b'"1970-01-01T00:00:00+00:00"'
Serializar claves dict
de tipo distinto de str
. Esto permite que las claves dict
sean una de las siguientes: str
, int
, float
, bool
, None
, datetime.datetime
, datetime.date
, datetime.time
, enum.Enum
y uuid.UUID
. A modo de comparación, la biblioteca estándar serializa str
, int
, float
, bool
o None
de forma predeterminada. Los puntos de referencia de orjson son más rápidos a la hora de serializar claves no str
que otras bibliotecas. Esta opción es más lenta para las teclas str
que la predeterminada.
> >> import orjson , datetime , uuid
> >> orjson . dumps (
{ uuid . UUID ( "7202d115-7ff3-4c81-a7c1-2a1f067b1ece" ): [ 1 , 2 , 3 ]},
option = orjson . OPT_NON_STR_KEYS ,
)
b'{"7202d115-7ff3-4c81-a7c1-2a1f067b1ece":[1,2,3]}'
> >> orjson . dumps (
{ datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 ): [ 1 , 2 , 3 ]},
option = orjson . OPT_NON_STR_KEYS | orjson . OPT_NAIVE_UTC ,
)
b'{"1970-01-01T00:00:00+00:00":[1,2,3]}'
Estos tipos generalmente se serializan como serían como valores, por ejemplo, datetime.datetime
sigue siendo una cadena RFC 3339 y respeta las opciones que la afectan. La excepción es que la serialización int
no respeta OPT_STRICT_INTEGER
.
Esta opción tiene el riesgo de crear claves duplicadas. Esto se debe a que los objetos que no son str
pueden serializarse en la misma str
que una clave existente, por ejemplo, {"1": true, 1: false}
. La última clave que se insertará en el dict
se serializará en último lugar y un deserializador JSON presumiblemente tomará la última aparición de una clave (en lo anterior, false
). El primer valor se perderá.
Esta opción es compatible con orjson.OPT_SORT_KEYS
. Si se utiliza la clasificación, tenga en cuenta que la clasificación es inestable y será impredecible para claves duplicadas.
> >> import orjson , datetime
> >> orjson . dumps (
{ "other" : 1 , datetime . date ( 1970 , 1 , 5 ): 2 , datetime . date ( 1970 , 1 , 3 ): 3 },
option = orjson . OPT_NON_STR_KEYS | orjson . OPT_SORT_KEYS
)
b'{"1970-01-03":3,"1970-01-05":2,"other":1}'
Esto mide la serialización de 589 KB de JSON que comprende una list
de 100 dict
en los que cada dict
tiene 365 claves int
ordenadas aleatoriamente que representan marcas de tiempo de época, así como una clave str
y el valor de cada clave es un entero único. En "claves str", las claves se convirtieron a str
antes de la serialización, y orjson todavía especifica option=orjson.OPT_NON_STR_KEYS
(que siempre es algo más lento).
Biblioteca | teclas str (ms) | claves int (ms) | claves int ordenadas (ms) |
---|---|---|---|
orjson | 0,5 | 0,93 | 2.08 |
json | 2.72 | 3.59 |
json está en blanco porque genera TypeError
al intentar ordenar antes de convertir todas las claves a str
. Esto se puede reproducir usando el script pynonstr
.
No serialice el campo microsecond
en instancias datetime.datetime
y datetime.time
.
> >> import orjson , datetime
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , 1 ),
)
b'"1970-01-01T00:00:00.000001"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , 1 ),
option = orjson . OPT_OMIT_MICROSECONDS ,
)
b'"1970-01-01T00:00:00"'
Pasar las instancias dataclasses.dataclass
al default
. Esto permite personalizar su salida, pero es mucho más lento.
> >> import orjson , dataclasses
> >>
@ dataclasses . dataclass
class User :
id : str
name : str
password : str
def default ( obj ):
if isinstance ( obj , User ):
return { "id" : obj . id , "name" : obj . name }
raise TypeError
> >> orjson . dumps ( User ( "3b1" , "asd" , "zxc" ))
b'{"id":"3b1","name":"asd","password":"zxc"}'
> >> orjson . dumps ( User ( "3b1" , "asd" , "zxc" ), option = orjson . OPT_PASSTHROUGH_DATACLASS )
TypeError : Type is not JSON serializable : User
> >> orjson . dumps (
User ( "3b1" , "asd" , "zxc" ),
option = orjson . OPT_PASSTHROUGH_DATACLASS ,
default = default ,
)
b'{"id":"3b1","name":"asd"}'
Paso a través de las instancias datetime.datetime
, datetime.date
y datetime.time
al default
. Esto permite serializar fechas y horas en un formato personalizado, por ejemplo, fechas HTTP:
> >> import orjson , datetime
> >>
def default ( obj ):
if isinstance ( obj , datetime . datetime ):
return obj . strftime ( "%a, %d %b %Y %H:%M:%S GMT" )
raise TypeError
> >> orjson . dumps ({ "created_at" : datetime . datetime ( 1970 , 1 , 1 )})
b'{"created_at":"1970-01-01T00:00:00"}'
> >> orjson . dumps ({ "created_at" : datetime . datetime ( 1970 , 1 , 1 )}, option = orjson . OPT_PASSTHROUGH_DATETIME )
TypeError : Type is not JSON serializable : datetime . datetime
> >> orjson . dumps (
{ "created_at" : datetime . datetime ( 1970 , 1 , 1 )},
option = orjson . OPT_PASSTHROUGH_DATETIME ,
default = default ,
)
b'{"created_at":"Thu, 01 Jan 1970 00:00:00 GMT"}'
Esto no afecta las fechas y horas en las claves dict
si se usa OPT_NON_STR_KEYS.
Subclases de paso a través de tipos integrados por default
.
> >> import orjson
> >>
class Secret ( str ):
pass
def default ( obj ):
if isinstance ( obj , Secret ):
return "******"
raise TypeError
> >> orjson . dumps ( Secret ( "zxc" ))
b'"zxc"'
> >> orjson . dumps ( Secret ( "zxc" ), option = orjson . OPT_PASSTHROUGH_SUBCLASS )
TypeError : Type is not JSON serializable : Secret
> >> orjson . dumps ( Secret ( "zxc" ), option = orjson . OPT_PASSTHROUGH_SUBCLASS , default = default )
b'"******"'
Esto no afecta la serialización de subclases como claves dict
si se usa OPT_NON_STR_KEYS.
Esto está en desuso y no tiene ningún efecto en la versión 3. En la versión 2, esto era necesario para serializar instancias dataclasses.dataclass
. Para obtener más información, consulte clase de datos.
Serializar instancias numpy.ndarray
. Para obtener más información, consulte numpy.
Esto está en desuso y no tiene ningún efecto en la versión 3. En la versión 2, esto era necesario para serializar instancias uuid.UUID
. Para obtener más información, consulte UUID.
Serializar claves dict
en orden. El valor predeterminado es serializar en un orden no especificado. Esto es equivalente a sort_keys=True
en la biblioteca estándar.
Esto se puede utilizar para garantizar que el orden sea determinista para hash o pruebas. Tiene una penalización sustancial en el rendimiento y no se recomienda en general.
> >> import orjson
> >> orjson . dumps ({ "b" : 1 , "c" : 2 , "a" : 3 })
b'{"b":1,"c":2,"a":3}'
> >> orjson . dumps ({ "b" : 1 , "c" : 2 , "a" : 3 }, option = orjson . OPT_SORT_KEYS )
b'{"a":3,"b":1,"c":2}'
Esto mide la serialización del dispositivo twitter.json sin clasificar y ordenado:
Biblioteca | sin clasificar (ms) | ordenado (ms) | contra orjson |
---|---|---|---|
orjson | 0,11 | 0.3 | 1 |
json | 1.36 | 1,93 | 6.4 |
El punto de referencia se puede reproducir utilizando el script pysort
.
La clasificación no tiene en cuenta la clasificación/localización:
> >> import orjson
> >> orjson . dumps ({ "a" : 1 , "ä" : 2 , "A" : 3 }, option = orjson . OPT_SORT_KEYS )
b'{"A":3,"a":1," xc3 xa4 ":2}'
Este es el mismo comportamiento de clasificación que la biblioteca estándar.
dataclass
también se serializa como mapas, pero esto no tiene ningún efecto sobre ellos.
Aplicar un límite de 53 bits a los números enteros. Por lo demás, el límite es de 64 bits, el mismo que el de la biblioteca estándar de Python. Para más información, consulte int.
Serializar una zona horaria UTC en instancias datetime.datetime
como Z
en lugar de +00:00
.
> >> import orjson , datetime , zoneinfo
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , tzinfo = zoneinfo . ZoneInfo ( "UTC" )),
)
b'"1970-01-01T00:00:00+00:00"'
> >> orjson . dumps (
datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 , tzinfo = zoneinfo . ZoneInfo ( "UTC" )),
option = orjson . OPT_UTC_Z
)
b'"1970-01-01T00:00:00Z"'
orjson.Fragment
incluye JSON ya serializado en un documento. Esta es una forma eficaz de incluir blobs JSON desde una memoria caché, un campo JSONB o un objeto serializado por separado sin deserializar primero los objetos Python mediante loads()
.
> >> import orjson
> >> orjson . dumps ({ "key" : "zxc" , "data" : orjson . Fragment ( b'{"a": "b", "c": 1}' )})
b'{"key":"zxc","data":{"a": "b", "c": 1}}'
No reformatea: orjson.OPT_INDENT_2
no afectará a un blob compacto ni un blob JSON con una bonita impresión se reescribirá como compacto.
La entrada debe ser bytes
o str
y entregarse como argumento posicional.
Esto genera orjson.JSONEncodeError
si se proporciona una str
y la entrada no es UTF-8 válida. De lo contrario, no realiza ninguna validación y es posible escribir JSON no válido. Esto no escapa a los personajes. Se prueba que la implementación no falla si se proporcionan cadenas no válidas o JSON no válidos.
def loads ( __obj : Union [ bytes , bytearray , memoryview , str ]) -> Any : ...
loads()
deserializa JSON a objetos Python. Deserializa los objetos dict
, list
, int
, float
, str
, bool
y None
.
Se aceptan bytes
, bytearray
, memoryview
y str
. Si la entrada existe como un objeto memoryview
, bytearray
u bytes
, se recomienda pasarlos directamente en lugar de crear un objeto str
innecesario. Es decir, orjson.loads(b"{}")
en lugar de orjson.loads(b"{}".decode("utf-8"))
. Esto tiene un menor uso de memoria y menor latencia.
La entrada debe ser UTF-8 válida.
orjson mantiene un caché de claves de mapa durante la duración del proceso. Esto provoca una reducción neta en el uso de memoria al evitar cadenas duplicadas. Las claves deben tener como máximo 64 bytes para almacenarse en caché y se almacenan 2048 entradas.
El bloqueo global del intérprete (GIL) se mantiene mientras dure la llamada.
Genera JSONDecodeError
si se le proporciona un tipo no válido o un JSON no válido. Esto incluye si la entrada contiene NaN
, Infinity
o -Infinity
, lo que permite la biblioteca estándar, pero no es JSON válido.
Genera JSONDecodeError
si una combinación de matriz u objeto se repite a 1024 niveles de profundidad.
JSONDecodeError
es una subclase de json.JSONDecodeError
y ValueError
. Esto es por compatibilidad con la biblioteca estándar.
orjson serializa instancias de dataclasses.dataclass
de forma nativa. Serializa instancias entre 40 y 50 veces más rápido que otras bibliotecas y evita una desaceleración grave que se observa en otras bibliotecas en comparación con la serialización dict
.
Se admite la transferencia de todas las variantes de clases de datos, incluidas las clases de datos que usan __slots__
, clases de datos congeladas, aquellas con atributos opcionales o predeterminados y subclases. Hay un beneficio de rendimiento al no usar __slots__
.
Biblioteca | dict (ms) | clase de datos (ms) | contra orjson |
---|---|---|---|
orjson | 0,43 | 0,95 | 1 |
json | 5.81 | 38.32 | 40 |
Esto mide la serialización de 555 KB de JSON, orjson de forma nativa y otras bibliotecas que utilizan default
para serializar la salida de dataclasses.asdict()
. Esto se puede reproducir usando el script pydataclass
.
Las clases de datos se serializan como mapas, con cada atributo serializado y en el orden indicado en la definición de clase:
> >> import dataclasses , orjson , typing
@ dataclasses . dataclass
class Member :
id : int
active : bool = dataclasses . field ( default = False )
@ dataclasses . dataclass
class Object :
id : int
name : str
members : typing . List [ Member ]
> >> orjson . dumps ( Object ( 1 , "a" , [ Member ( 1 , True ), Member ( 2 )]))
b'{"id":1,"name":"a","members":[{"id":1,"active":true},{"id":2,"active":false}]}'
orjson serializa objetos datetime.datetime
al formato RFC 3339, por ejemplo, "1970-01-01T00:00:00+00:00". Este es un subconjunto de ISO 8601 y es compatible con isoformat()
en la biblioteca estándar.
> >> import orjson , datetime , zoneinfo
> >> orjson . dumps (
datetime . datetime ( 2018 , 12 , 1 , 2 , 3 , 4 , 9 , tzinfo = zoneinfo . ZoneInfo ( "Australia/Adelaide" ))
)
b'"2018-12-01T02:03:04.000009+10:30"'
> >> orjson . dumps (
datetime . datetime ( 2100 , 9 , 1 , 21 , 55 , 2 ). replace ( tzinfo = zoneinfo . ZoneInfo ( "UTC" ))
)
b'"2100-09-01T21:55:02+00:00"'
> >> orjson . dumps (
datetime . datetime ( 2100 , 9 , 1 , 21 , 55 , 2 )
)
b'"2100-09-01T21:55:02"'
datetime.datetime
admite instancias con un tzinfo
que es None
, datetime.timezone.utc
, una instancia de zona horaria del módulo zoneinfo
de python3.9+ o una instancia de zona horaria de las bibliotecas de terceros pendulum
, pytz
o dateutil
/ arrow
.
Es más rápido utilizar zoneinfo.ZoneInfo
de la biblioteca estándar para zonas horarias.
Los objetos datetime.time
no deben tener un tzinfo
.
> >> import orjson , datetime
> >> orjson . dumps ( datetime . time ( 12 , 0 , 15 , 290 ))
b'"12:00:15.000290"'
Los objetos datetime.date
siempre se serializarán.
> >> import orjson , datetime
> >> orjson . dumps ( datetime . date ( 1900 , 1 , 2 ))
b'"1900-01-02"'
Los errores con tzinfo
provocan que se genere JSONEncodeError
.
Para deshabilitar la serialización de objetos datetime
especifique la opción orjson.OPT_PASSTHROUGH_DATETIME
.
Para utilizar el sufijo "Z" en lugar de "+00:00" para indicar la hora UTC ("Zulu"), utilice la opción orjson.OPT_UTC_Z
.
Para asumir que las fechas sin zona horaria son UTC, use la opción orjson.OPT_NAIVE_UTC
.
orjson serializa enumeraciones de forma nativa. Las opciones se aplican a sus valores.
> >> import enum , datetime , orjson
> >>
class DatetimeEnum ( enum . Enum ):
EPOCH = datetime . datetime ( 1970 , 1 , 1 , 0 , 0 , 0 )
> >> orjson . dumps ( DatetimeEnum . EPOCH )
b'"1970-01-01T00:00:00"'
> >> orjson . dumps ( DatetimeEnum . EPOCH , option = orjson . OPT_NAIVE_UTC )
b'"1970-01-01T00:00:00+00:00"'
Las enumeraciones con miembros que no son tipos compatibles se pueden serializar usando default
:
> >> import enum , orjson
> >>
class Custom :
def __init__ ( self , val ):
self . val = val
def default ( obj ):
if isinstance ( obj , Custom ):
return obj . val
raise TypeError
class CustomEnum ( enum . Enum ):
ONE = Custom ( 1 )
> >> orjson . dumps ( CustomEnum . ONE , default = default )
b'1'
orjson serializa y deserializa flotantes de doble precisión sin pérdida de precisión y con un redondeo consistente.
orjson.dumps()
serializa Nan, Infinity y -Infinity, que no son compatibles con JSON, como null
:
> >> import orjson , json
> >> orjson . dumps ([ float ( "NaN" ), float ( "Infinity" ), float ( "-Infinity" )])
b'[null,null,null]'
> >> json . dumps ([ float ( "NaN" ), float ( "Infinity" ), float ( "-Infinity" )])
'[NaN, Infinity, -Infinity]'
orjson serializa y deserializa enteros de 64 bits de forma predeterminada. El rango admitido es un mínimo de un entero de 64 bits con signo (-9223372036854775807) hasta un máximo de un entero de 64 bits sin signo (18446744073709551615). Esto es ampliamente compatible, pero hay implementaciones que sólo admiten 53 bits para números enteros, por ejemplo, navegadores web. Para esas implementaciones, dumps()
se puede configurar para generar un JSONEncodeError
en valores que excedan el rango de 53 bits.
> >> import orjson
> >> orjson . dumps ( 9007199254740992 )
b'9007199254740992'
> >> orjson . dumps ( 9007199254740992 , option = orjson . OPT_STRICT_INTEGER )
JSONEncodeError : Integer exceeds 53 - bit range
>> > orjson . dumps ( - 9007199254740992 , option = orjson . OPT_STRICT_INTEGER )
JSONEncodeError : Integer exceeds 53 - bit range
orjson serializa de forma nativa numpy.ndarray
y numpy.float64
, numpy.float32
, numpy.float16
( numpy.half
), numpy.int64
, numpy.int32
, numpy.int16
, numpy.int8
, numpy.uint64
, numpy.uint32
, numpy.uint16
, numpy.uint8
, numpy.uintp
, numpy.intp
, numpy.datetime64
y numpy.bool
instancias.
orjson es compatible tanto con numpy v1 como con v2.
orjson es más rápido que todas las bibliotecas comparadas a la hora de serializar numerosas instancias. La serialización de datos numerosos requiere especificar option=orjson.OPT_SERIALIZE_NUMPY
.
> >> import orjson , numpy
> >> orjson . dumps (
numpy . array ([[ 1 , 2 , 3 ], [ 4 , 5 , 6 ]]),
option = orjson . OPT_SERIALIZE_NUMPY ,
)
b'[[1,2,3],[4,5,6]]'
La matriz debe ser una matriz C contigua ( C_CONTIGUOUS
) y uno de los tipos de datos admitidos.
Tenga en cuenta una diferencia entre serializar numpy.float32
usando ndarray.tolist()
o orjson.dumps(..., option=orjson.OPT_SERIALIZE_NUMPY)
: tolist()
se convierte en un double
antes de serializar y la ruta nativa de orjson no. Esto puede dar como resultado un redondeo diferente.
Las instancias numpy.datetime64
se serializan como cadenas RFC 3339 y las opciones de fecha y hora las afectan.
> >> import orjson , numpy
> >> orjson . dumps (
numpy . datetime64 ( "2021-01-01T00:00:00.172" ),
option = orjson . OPT_SERIALIZE_NUMPY ,
)
b'"2021-01-01T00:00:00.172000"'
> >> orjson . dumps (
numpy . datetime64 ( "2021-01-01T00:00:00.172" ),
option = (
orjson . OPT_SERIALIZE_NUMPY |
orjson . OPT_NAIVE_UTC |
orjson . OPT_OMIT_MICROSECONDS
),
)
b'"2021-01-01T00:00:00+00:00"'
Si una matriz no es una matriz C contigua, contiene un tipo de datos no admitido o contiene un numpy.datetime64
usando una representación no admitida (por ejemplo, picosegundos), orjson pasa al default
. De default
, se puede especificar obj.tolist()
.
Si una matriz no está en el endianismo nativo, por ejemplo, una matriz de valores big-endian en un sistema little-endian, se genera orjson.JSONEncodeError
.
Si una matriz tiene un formato incorrecto, se genera orjson.JSONEncodeError
.
Esto mide la serialización de 92MiB de JSON de un numpy.ndarray
con dimensiones de (50000, 100)
y valores numpy.float64
:
Biblioteca | Latencia (ms) | Diferencia RSS (MiB) | contra orjson |
---|---|---|---|
orjson | 105 | 105 | 1 |
json | 1.481 | 295 | 14.2 |
Esto mide la serialización de 100MiB de JSON de un numpy.ndarray
con dimensiones de (100000, 100)
y valores numpy.int32
:
Biblioteca | Latencia (ms) | Diferencia RSS (MiB) | contra orjson |
---|---|---|---|
orjson | 68 | 119 | 1 |
json | 684 | 501 | 10.1 |
Esto mide la serialización de 105MiB de JSON de un numpy.ndarray
con dimensiones de (100000, 200)
y valores numpy.bool
:
Biblioteca | Latencia (ms) | Diferencia RSS (MiB) | contra orjson |
---|---|---|---|
orjson | 50 | 125 | 1 |
json | 573 | 398 | 11.5 |
En estos puntos de referencia, orjson serializa de forma nativa y json
serializa ndarray.tolist()
de forma default
. La columna RSS mide el uso máximo de memoria durante la serialización. Esto se puede reproducir usando el script pynumpy
.
orjson no tiene una dependencia de instalación o compilación en numpy. La implementación es independiente y lee numpy.ndarray
usando PyArrayInterface
.
orjson es estricto con respecto a la conformidad con UTF-8. Esto es más estricto que el módulo json de la biblioteca estándar, que serializará y deserializará sustitutos UTF-16, por ejemplo, "ud800", que no son UTF-8 no válidos.
Si orjson.dumps()
se le asigna una str
que no contiene UTF-8 válido, se genera orjson.JSONEncodeError
. Si loads()
recibe UTF-8 no válido, se genera orjson.JSONDecodeError
.
> >> import orjson , json
> >> orjson . dumps ( ' ud800 ' )
JSONEncodeError : str is not valid UTF - 8 : surrogates not allowed
>> > json . dumps ( ' ud800 ' )
'" \ ud800"'
> >> orjson . loads ( '" \ ud800"' )
JSONDecodeError : unexpected end of hex escape at line 1 column 8 : line 1 column 1 ( char 0 )
> >> json . loads ( '" \ ud800"' )
' ud800 '
Para hacer un mejor esfuerzo para deserializar la entrada incorrecta, primero decodifique bytes
usando el argumento replace
o lossy
para errors
:
> >> import orjson
> >> orjson . loads ( b'" xed xa0 x80 "' )
JSONDecodeError : str is not valid UTF - 8 : surrogates not allowed
>> > orjson . loads ( b'" xed xa0 x80 "' . decode ( "utf-8" , "replace" ))
'���'
orjson serializa instancias uuid.UUID
al formato RFC 4122, por ejemplo, "f81d4fae-7dec-11d0-a765-00a0c91e6bf6".
> >> import orjson , uuid
> >> orjson . dumps ( uuid . uuid5 ( uuid . NAMESPACE_DNS , "python.org" ))
b'"886313e1-3b8a-5372-9b90-0c9aee199e5d"'
La biblioteca cuenta con pruebas completas. Hay pruebas contra dispositivos en los repositorios JSONTestSuite y Nativejson-benchmark. Está probado para no chocar con la Gran Lista de Cuerdas Traviesas. Está probado para no perder memoria. Está probado para no chocar y no aceptar UTF-8 no válido. Hay pruebas de integración que ejercitan el uso de la biblioteca en servidores web (gunicorn usando trabajadores multiproceso/bifurcados) y cuando es multiproceso. También utiliza algunas pruebas de la biblioteca ultrajson.
orjson es la más correcta de las bibliotecas comparadas. Este gráfico muestra cómo cada biblioteca maneja 342 dispositivos JSON combinados de las pruebas JSONTestSuite y Nativejson-benchmark:
Biblioteca | Documentos JSON no válidos no rechazados | Documentos JSON válidos no deserializados |
---|---|---|
orjson | 0 | 0 |
json | 17 | 0 |
Esto muestra que todas las bibliotecas deserializan JSON válido, pero solo orjson rechaza correctamente los dispositivos JSON no válidos proporcionados. Los errores se deben en gran medida a la aceptación de cadenas y números no válidos.
El gráfico anterior se puede reproducir utilizando el script pycorrectness
.
El rendimiento de serialización y deserialización de orjson es consistentemente mejor que el json
de la biblioteca estándar. Los gráficos siguientes ilustran algunos documentos de uso común.
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 0.1 | 8453 | 1 |
json | 1.3 | 765 | 11.1 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 0,5 | 1889 | 1 |
json | 2.2 | 453 | 4.2 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 0,01 | 103693 | 1 |
json | 0,13 | 7648 | 13.6 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 0,04 | 23264 | 1 |
json | 0.1 | 10430 | 2.2 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 0.3 | 3975 | 1 |
json | 3 | 338 | 11.8 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 1.3 | 781 | 1 |
json | 4 | 250 | 3.1 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 2.5 | 399 | 1 |
json | 29,8 | 33 | 11.9 |
Biblioteca | Latencia media (milisegundos) | Operaciones por segundo | Relativo (latencia) |
---|---|---|---|
orjson | 3 | 333 | 1 |
json | 18 | 55 | 6 |
Lo anterior se midió usando Python 3.11.10 en un contenedor Fedora 42 en una máquina x86-64-v4 usando el artefacto orjson-3.10.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
en PyPI. Los resultados de latencia se pueden reproducir utilizando el script pybench
.
Probablemente pip
deba actualizarse a la versión 20.3 o posterior para admitir los últimos formatos de rueda manylinux_x_y o universal2.
Esto sucede cuando no hay ruedas binarias (como manylinux) para su plataforma en PyPI. Puede instalar Rust a través de rustup
o un administrador de paquetes y luego se compilará.
No. Esto requiere un esquema que especifique qué tipos se esperan y cómo manejar los errores, etc. Esto lo solucionan las bibliotecas de validación de datos de un nivel superior.
str
? Número bytes
es el tipo correcto para un blob serializado.
No. orjsonl puede ser apropiado.
No, es compatible con RFC 8259.
Para empaquetar orjson se requiere al menos Rust 1.72 y la herramienta de compilación maturin. El comando de compilación recomendado es:
maturin build --release --strip
También se beneficia de tener un entorno de compilación C para compilar un backend de deserialización más rápido. Vea las compilaciones manylinux_2_28
de este proyecto para ver un ejemplo usando clang y LTO.
La propia CI del proyecto se prueba contra nightly-2024-11-22
y estable 1.72. Es prudente fijar la versión nocturna porque ese canal puede introducir cambios importantes. Hay un beneficio significativo en el rendimiento al usarlo todas las noches.
orjson se prueba para amd64, aarch64 e i686 en Linux y realiza compilaciones cruzadas para arm7, ppc64le y s390x. Se prueba para aarch64 o amd64 en macOS y se realiza una compilación cruzada para el otro, según la versión. Para Windows está probado en amd64 e i686.
No existen dependencias de tiempo de ejecución distintas de libc.
La distribución de código fuente en PyPI contiene el código fuente de todas las dependencias y se puede crear sin acceso a la red. El archivo se puede descargar desde https://files.pythonhosted.org/packages/source/o/orjson/orjson-${version}.tar.gz
.
Las pruebas de Orjson están incluidas en la distribución fuente de PyPI. Los requisitos para ejecutar las pruebas se especifican en test/requirements.txt
. Las pruebas deben ejecutarse como parte de la compilación. Se puede ejecutar con pytest -q test
.
orjson fue escrito por ijl