This guide will walk you through the basics of using lodum to serialize and deserialize Python objects.
Define your data structure
Use the @lodum decorator on your class. You can use standard __init__ methods or dataclasses. Make sure to include type hints, as lodum uses them to understand your data.
Dataclass style
__init__ style
from lodum import lodum
from dataclasses import dataclass
@lodum
@dataclass
class User :
name: str
age: int
is_active: bool
Type hints are required. lodum uses them to generate optimized serialization code.
Encode to JSON
Use the json.dumps() function to convert an instance of your class into a JSON string:
from lodum import json
user = User( name = "Alex" , age = 30 , is_active = True )
# Encode the object to a JSON string
json_string = json.dumps(user)
print (json_string)
# Output: {"name": "Alex", "age": 30, "is_active": true}
Decode from JSON
Use the json.loads() function to decode a JSON string back to a Python object:
json_data = '{"name": "Barbara", "age": 25, "is_active": false}'
# Decode the JSON string to a User object
barbara = json.loads(User, json_data)
print ( f "Name: { barbara.name } , Age: { barbara.age } , Active: { barbara.is_active } " )
# Output: Name: Barbara, Age: 25, Active: False
The first argument to loads() is the class type. This enables full type validation and ensures you get the correct object type back.
You can easily switch between formats. lodum supports JSON, YAML, TOML, MessagePack, CBOR, BSON, and Pickle:
from lodum import json, yaml, toml
user = User( name = "Alex" , age = 30 , is_active = True )
# Encode to different formats
json_output = json.dumps(user)
yaml_output = yaml.dumps(user)
toml_output = toml.dumps(user)
print (yaml_output)
# Output:
# name: Alex
# age: 30
# is_active: true
# Decode from YAML
user_from_yaml = yaml.loads(User, yaml_output)
Field customization
Customize individual fields using the field() function:
from lodum import lodum, field, json
@lodum
class User :
def __init__ (
self ,
# Rename 'user_id' to 'id' in the output
user_id : int = field( rename = "id" , default = 0 ),
# This field is required
email : str = "" ,
# This field will not be included in the output
password_hash : str = field( skip_serializing = True , default = "" ),
# If 'prefs' is missing on decoding, it will default to an empty dict
prefs : dict = field( default_factory = dict ),
):
self .user_id = user_id
self .email = email
self .password_hash = password_hash
self .prefs = prefs
# Encode a user
user = User( email = "[email protected] " , user_id = 123 , password_hash = "secret" )
print (json.dumps(user))
# Output: {"id": 123, "email": "[email protected] ", "prefs": {}}
# Decode a user
user_data = '{"id": 456, "email": "[email protected] "}'
user = json.loads(User, user_data)
print (user.user_id) # 456
print (user.prefs) # {}
Supported field options
Use a different name for the field in the output
Exclude the field from the output
Provide a default value if the field is missing during decoding
Provide a zero-argument function to call for a default value
A function to call to encode the field’s value
A function to call to decode the field’s value
validate
Callable[[Any], None] | list
A function or list of functions to validate the field’s value during decoding
Validation
lodum includes built-in validators to ensure your data meets specific criteria:
from lodum import lodum, field, json
from lodum.validators import Range, Length, Match, OneOf
@lodum
class Product :
def __init__ (
self ,
name : str = field( validate = Length( min = 3 , max = 50 )),
price : float = field( validate = Range( min = 0 )),
category : str = field( validate = OneOf([ "electronics" , "books" , "clothing" ])),
code : str = field( validate = Match( r " ^ [ A-Z ] {2} - \d {4} $ " ))
):
self .name = name
self .price = price
self .category = category
self .code = code
# This will raise a DeserializationError
try :
json.loads(
Product,
'{"name": "A", "price": -10, "category": "food", "code": "abc"}'
)
except Exception as e:
print ( f "Validation failed: { e } " )
Built-in validators
Validates that a value is within a specified range Range( min = 0 , max = 100 )
Range( min = 0 ) # No maximum
Validates that a collection has a length within a specified range Length( min = 3 , max = 50 )
Length( min = 1 ) # At least 1 item
Validates that a string matches a regular expression pattern Match( r " ^ [ A-Z ] {2} - \d {4} $ " )
Validates that a value is one of a set of allowed values OneOf([ "small" , "medium" , "large" ])
Error reporting
lodum provides detailed path information when deserialization fails:
from lodum import lodum, json
from lodum.exception import DeserializationError
@lodum
class User :
def __init__ ( self , name : str , age : int ):
self .name = name
self .age = age
json_data = '{"name": "Alex", "age": "not_an_int"}'
try :
json.loads(User, json_data)
except DeserializationError as e:
print (e)
# Output: Error at age: Expected int, got str
The path tracking works through nested objects, lists, and dictionaries (e.g., root.users[2].id).
Working with dictionaries
Convert objects to and from plain Python dictionaries:
import lodum
@lodum
class User :
def __init__ ( self , user_id : int = lodum.field( rename = "id" ), name : str = "" ):
self .user_id = user_id
self .name = name
user = User( user_id = 1 , name = "Alex" )
# Convert to dictionary
data = lodum.asdict(user)
print (data)
# Output: {"id": 1, "name": "Alex"}
# Convert from dictionary
new_user = lodum.fromdict(User, { "id" : 2 , "name" : "Sam" })
print (new_user.user_id) # 2
JSON schema generation
Generate standard JSON Schema for any @lodum-decorated class:
import lodum
import json
@lodum
class User :
def __init__ ( self , id : int , name : str ):
self .id = id
self .name = name
# Generate the schema
schema = lodum.schema(User)
print (json.dumps(schema, indent = 2 ))
# Output:
# {
# "type": "object",
# "properties": {
# "id": { "type": "integer" },
# "name": { "type": "string" }
# },
# "required": ["id", "name"]
# }
This is particularly useful for documenting your data models or for use with LLM tool definitions.
Streaming serialization
For extremely large datasets, lodum supports O(1) memory streaming serialization:
import sys
from lodum import lodum, json
@lodum
class LargeData :
def __init__ ( self , items : list[ int ]):
self .items = items
# Serialize a large object directly to stdout (or a file)
data = LargeData( items = list ( range ( 1000000 )))
json.dump(data, sys.stdout)
For loading, json.stream() provides lazy, iterator-based deserialization of JSON arrays.
Next steps
API reference Explore the complete API documentation
Migration guide Migrating from another library?
Architecture Learn how lodum works under the hood
Performance See detailed benchmark results