I'd like to pass object state between two Python programs (one is my own code running standalone, one is a Pyramid view), and different namespaces. Somewhat related questions are here or here, but I can't quite follow through with them for my scenario.
My own code defines a global class (i.e. __main__
namespace) of somewhat complexish structure:
# An instance of this is a colorful mess of nested lists and sets and dicts.
class MyClass :
def __init__(self) :
data = set()
more = dict()
...
def do_sth(self) :
...
At some point I pickle an instance of this class:
c = MyClass()
# Fill c with data.
# Pickle and write the MyClass instance within the __main__ namespace.
with open("my_c.pik", "wb") as f :
pickle.dump(c, f, -1)
A hexdump -C my_c.pik
shows that the first couple of bytes contain __main__.MyClass
from which I assume that the class is indeed defined in the global namespace, and that this is somehow a requirement for reading the pickle. Now I'd like to load this pickled MyClass
instance from within a Pyramid view, which I assume is a different namespace:
# In Pyramid (different namespace) read the pickled MyClass instance.
with open("my_c.pik", "rb") as f :
c = pickle.load(f)
But that results in the following error:
File ".../views.py", line 60, in view_handler_bla
c = pickle.load(f)
AttributeError: 'module' object has no attribute 'MyClass'
It seems to me that the MyClass
definition is missing in whatever namespace the view code executes? I had hoped (assumed) that pickling is a somewhat opaque process which allows me to read a blob of data into whichever place I chose. (More on Python's class names and namespaces is here.)
How can I handle this properly? (Ideally without having to import stuff across...) Can I somehow find the current namespace and inject MyClass
(like this answer seems to suggest)?
Poor Solution
It seems to me that if I refrain from defining and using MyClass
and instead fall back to plain built-in datatypes, this wouldn't be a problem. In fact, I could "serialize" the MyClass
object into a sequence of calls that pickle the individual elements of the MyClass
instance:
# 'Manual' serialization of c works, because all elements are built-in types.
pickle.dump(c.data, f, -1)
pickle.dump(c.more, f, -1)
...
This would defeat the purpose of wrapping data into classes though.
Note
Pickling takes care only of the state of a class, not of any functions defined in the scope of the class (e.g. do_sth()
in the above example). That means that loading a MyClass
instance into a different namespace without the proper class definition loads only the instance data; calling a missing function like do_sth()
will cause an AttributeError.