title: Python Native Serialization sidebar_position: 2 id: native license: | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Python native serialization is the Python-only wire mode selected with xlang=False. Use it when every writer and reader is Python and the payload should follow Python's object model instead of the portable xlang type system.
Use Cross-Language Interoperability, the default Python mode, when bytes must be read by Java, C++, Go, Rust, JavaScript/TypeScript, C#, Swift, Dart, Scala, Kotlin, or another non-Python Fory implementation.
Use native serialization when:
pickle or cloudpickle for Python-only object graphs.Native mode can serialize Python-specific values such as global functions, local functions, lambdas, local classes, methods, and objects customized with __getstate__, __setstate__, __reduce__, or __reduce_ex__. Those values are not valid xlang payloads.
Create Fory with xlang=False:
import pyfory fory = pyfory.Fory(xlang=False, ref=False, strict=True)
Keep strict=True for registered, trusted type surfaces. Use strict=False only when native-mode payloads need dynamic Python types such as functions, local classes, or objects reconstructed by reduction hooks.
import pyfory fory = pyfory.Fory(xlang=False, ref=True, strict=False) data = fory.dumps({"name": "Alice", "age": 30, "scores": [95, 87, 92]}) print(fory.loads(data)) from dataclasses import dataclass @dataclass class Person: name: str age: int person = Person("Bob", 25) data = fory.dumps(person) print(fory.loads(data)) # Person(name='Bob', age=25)
Use dumps/loads for pickle-style APIs, or serialize/deserialize when matching the xlang API shape in code that switches modes explicitly.
Native mode can reconstruct Python objects that execute import and construction logic during deserialization. Treat untrusted native-mode bytes the same way you would treat untrusted pickle bytes.
strict=True when deserializing data that should contain only registered or built-in types.strict=False only for trusted payloads that require dynamic Python classes or functions.policy= deserialization policy when dynamic types are required but the accepted type surface should still be restricted.See Functions, Classes, and Methods for callable and type values, then Serialization Hooks for reduction, state, construction, and pickle/cloudpickle migration.
Enable ref=True when object identity, shared references, or cycles must round-trip:
import pyfory fory = pyfory.Fory(xlang=False, ref=True, strict=True) node = {} node["self"] = node data = fory.dumps(node) decoded = fory.loads(data) assert decoded["self"] is decoded
Disable reference tracking for value-shaped payloads that do not need identity preservation. It keeps the payload smaller and the hot path simpler.
Python native mode can use pickle protocol 5-style out-of-band buffers for large binary payloads and data structures backed by external memory:
import pickle import pyfory data = b"Large binary data" pickle_buffer = pickle.PickleBuffer(data) buffer_objects = [] fory = pyfory.Fory(xlang=False, ref=True, strict=False) serialized = fory.dumps(pickle_buffer, buffer_callback=buffer_objects.append) buffers = [obj.getbuffer() for obj in buffer_objects] decoded = fory.loads(serialized, buffers=buffers) assert bytes(decoded.raw()) == data
Use this when the payload stays in Python and large buffers should avoid extra copies. See Out-of-Band Serialization.
| Requirement | Use native serialization | Use xlang serialization |
|---|---|---|
| Python-only payloads | Yes | Optional |
| Non-Python readers or writers | No | Yes |
| Functions, lambdas, local classes | Yes | No |
__reduce__ / __getstate__ object hooks | Yes | No |
| Pickle/cloudpickle replacement | Yes | No |
| Portable type mapping across languages | No | Yes |
import pyfory import pickle import timeit fory = pyfory.Fory(xlang=False, ref=True, strict=False) obj = {f"key{i}": f"value{i}" for i in range(10000)} print(f"Fory: {timeit.timeit(lambda: fory.dumps(obj), number=1000):.3f}s") print(f"Pickle: {timeit.timeit(lambda: pickle.dumps(obj), number=1000):.3f}s")
The writer is using native serialization. Rebuild it with xlang=True, register portable schemas on every peer, and avoid Python-only values such as lambdas or local classes.
Use strict=False for trusted payloads and provide a deserialization policy= when only selected dynamic types should be accepted.
Create the Fory instance with ref=True.
Keep the payload in native mode. Xlang mode does not execute Python __reduce__, __reduce_ex__, __getstate__, or __setstate__ object reconstruction hooks.
Fory options