__reduce__ / __reduce_ex__

Added in v2.3 · Updated April 1, 2026 · Dunder Methods
stdlib pickle serialization copy magic-methods

Signature and Return Value

__reduce__ and __reduce_ex__ control how Python serializes your objects. Pickle, copy, and shelve all call these methods to pack and rebuild your data.

def __reduce__(self) -> str | Tuple
def __reduce_ex__(self, protocol: int) -> str | Tuple

__reduce__ takes no arguments beyond self. __reduce_ex__ receives the pickle protocol version. protocol is an int specifying the pickle protocol version (0–5); the method can branch on this value to produce different output per protocol.

Both methods return either a string or a tuple.

String Return

If you return a string, pickle treats it as the name of a global variable and stores whatever object that name refers to. This is the simplest path and works well for singletons.

import pickle

SPAM = "eggs"

class Wrapper:
    def __init__(self, value):
        self.value = value

    def __reduce__(self):
        return "SPAM"  # lookup the global named SPAM

w = Wrapper(42)
data = pickle.dumps(w)
restored = pickle.loads(data)
print(restored)  # 'eggs'

Tuple Return (2–5 items)

Returning a tuple gives you full control over reconstruction. The tuple must contain 2 to 5 items:

ItemsFormatWhat happens
2(callable, args)Calls callable(*args) to build the object
3(callable, args, state)Same, then calls obj.__setstate__(state)
4(callable, args, state, list_items)Same as 3, then extends the object with list_items
5(callable, args, state, list_items, dict_items)Same as 4, then updates the object with dict_items

Any trailing items you don’t need can be omitted or set to None.

Minimal Example: 2-Item Tuple

The most common pattern returns the class and its construction arguments:

import pickle

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __reduce__(self):
        return (self.__class__, (self.x, self.y))

p = Point(3, 4)
data = pickle.dumps(p)
restored = pickle.loads(data)
print(restored.x, restored.y)  # 3 4

Restoring State with __setstate__

When you return a 3-item tuple, pickle calls __setstate__ on the reconstructed object with your provided state. This separates reconstruction (creating the object) from restoring its internal state.

import pickle

class FrozenPoint:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self._frozen = True

    def __reduce__(self):
        return (
            self.__class__,
            (0, 0),                        # args for __init__ (ignored)
            {'x': self.x, 'y': self.y, '_frozen': self._frozen}
        )

    def __setstate__(self, state):
        self.x = state['x']
        self.y = state['y']
        self._frozen = state['_frozen']

fp = FrozenPoint(10, 20)
data = pickle.dumps(fp)
restored = pickle.loads(data)
print(restored.x, restored.y, restored._frozen)  # 10 20 True

__init__ received (0, 0) — values we threw away. The real data came through __setstate__.

__reduce_ex__ for Protocol-Aware Serialization

__reduce_ex__ receives the pickle protocol version, letting you adjust behavior across Python versions. When __reduce_ex__ is defined, pickle prefers it over __reduce__.

import copy
import pickle

class Node:
    def __init__(self, value, children=None):
        self.value = value
        self.children = children or []

    def __reduce_ex__(self, protocol):
        return (
            self.__class__,
            (self.value, []),
            None,               # no custom state
            self.children,      # list_items: restore the children list
            None                # no dict_items
        )

    def __setstate__(self, state):
        pass  # state is None, nothing to restore

root = Node("root", [Node("leaf")])
copied = copy.deepcopy(root)
print(copied.children[0].value)  # leaf

What Calls __reduce__

These methods are invoked by several stdlib tools:

  • pickle.dump() / pickle.dumps() / pickle.load() / pickle.loads()
  • copy.copy() and copy.deepcopy()
  • shelve.open() (which uses pickle under the hood)
  • marshall (deprecated)

Common Gotchas

__setstate__ is mandatory when returning state.

If your tuple has 3+ items and you include state, your class must define __setstate__. Omitting it raises AttributeError during unpickling.

Returning mutable state as the same reference.

If you return a list or dict as your state and intend to modify it in __setstate__, pickle may treat it as the same object. Return a copy of mutable state to avoid subtle aliasing bugs.

__slots__ without __dict__.

Classes using __slots__ and no __dict__ need to return slot values as a plain tuple or primitives. The reconstruction callable must handle slot restoration explicitly in __setstate__.

Security: never unpickle untrusted data.

__reduce__ can return arbitrary callables. A malicious pickle payload can execute arbitrary code during unpickling. Use json or similar safe formats when data comes from untrusted sources.

See Also