3.14.6 Subclassing Unpicklers
By default, unpickling will import any class that it finds in the pickle data. You can
control exactly what gets unpickled and what gets called by customizing your unpickler.
Unfortunately, exactly how you do this is different depending on whether you're using pickle or cPickle.3.10.
In the pickle module, you need to derive a subclass from Unpickler, overriding the load_global() method. load_global() should read two lines from the pickle data stream where the
first line will the name of the module containing the class and the second line will be the
name of the instance's class. It then looks up the class, possibly importing the module and
digging out the attribute, then it appends what it finds to the unpickler's stack. Later on,
this class will be assigned to the __class__ attribute of an empty
class, as a way of magically creating an instance without calling its class's __init__(). Your job (should you choose to accept it), would be to have load_global() push onto the unpickler's stack, a known safe version of any
class you deem safe to unpickle. It is up to you to produce such a class. Or you could raise
an error if you want to disallow all unpickling of instances. If this sounds like a hack,
you're right. Refer to the source code to make this work.
Things are a little cleaner with cPickle, but not by much. To
control what gets unpickled, you can set the unpickler's find_global
attribute to a function or
None. If it is
None then any attempts to
unpickle instances will raise an UnpicklingError. If it is a
function, then it should accept a module name and a class name, and return the corresponding
class object. It is responsible for looking up the class and performing any necessary imports,
and it may raise an error to prevent instances of the class from being unpickled.
The moral of the story is that you should be really careful about the source of the strings
your application unpickles.
- A word of caution: the mechanisms described here use internal attributes and methods,
which are subject to change in future versions of Python. We intend to someday provide a
common interface for controlling this behavior, which will work in either pickle or cPickle.