Source: đź“– Effective Python item 68
copyreg
to load outdated class instances reliablyThe pickle
module is intended to make object serialisation and desirialisation easy, but it is not intended to be completely robust beyond trivial use cases. For example, loading an old object instance after the overarching class' attributes have changed will result in an object which doesn't account for the changed class attributes—it will be a carbon copy of the original object even if the class it belongs to has changed.
To fix this problem, copyreg
can be used to define behaviour for unpickling an object back into a program. To do this, we must define a constructor (__init__
) function with keyword arguments and default values, and a helper function that returns a function to use for unpickling along with the parameters to be passed into the new object instance:
import copyreg
import pickle
class GameState():
def __init__(self, level=1, lives=5): # keyword arguments and default values
self.level = level
self.lives lives
def pickle_game_state(game_state_object):
kwargs = game_state_object.__dict__ # pulling out parameters into a variable
return unpickle_game_state, (kwargs,) # returning an unpickling func (defined below) and the kwargs to be used
def unpickle_game_state(kwargs):
return GameState(**kwargs) # returns a GameState instance with the kwargs as arguments
copyreg.pickle(GameState, pickle_game_state) # registering the function to be used for serialising and deserialising
The object can now be pickled and unpickled and be kept up-to date with changes to its overarching class, as each time the object is unpickled back into the program a GameState
instance is created using the **kwargs
arguments, meaning that any missing arguments will be set to the default value upon instantiation.