Uncorrelated February 2016

How can I make a Python deserialization function useable from another module?

I have some serialization and deserialization code which works well within one module (and within the universe of classes I care about). E.g.

class A(...):
    ...

class B(...):
    ...

def serialize( obj ):
    ...

def deserialize( string ):
    ...

assert( obj == deserialize( serialize( obj ) ) )

However, if I define a class in another module and import serialize and deserialize there, serialization works but I have a problem with deserialization. The deserialization function doesn't "know" about the class definition in the other module and can't instantiate an instance.

So far, I've used two different ways to work around this. One is by passing globals() and locals() into deserialize which then calls eval with them. Another has the caller pass in __name__ and deserialize call inspect.getmembers( sys.modules[ passedInName ] ). I could also require registering every serializable class in some list visible to deserialize.

But, I don't like any of those workarounds. Is there a better way?

(If it matters I need to use Python 2.7 because that's what we have at work.)

ADDED: I've coded up a version of the "register every serializable class in some list" strategy based on the ABCMeta metaclass which doesn't seem too horrible. It does involve looking in _abc_registry which feels a little wrong.

Answers


Jan Vlcinsky February 2016

One problem is probably in your last test:

assert( obj == deserialize( serialize( obj ) ) )

The objects will be "practically equal", but there will be two different instances of the same class, having all members the same.

You may check it by asking the objects for id(obj) value and you will get different values.

To fix that (if you want to allow two different instances being equal) is to add __eq__ to your classes.

Here is my attempt to define such classes plus added serialize and deserialize using JSON string. To show, that serialize and deserialize function may live in other module than classes, they are put into different module:

File classroom.py:

class A(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __repr__(self):
        templ = "<A: a:{self.a} b: {self.b}>"
        return templ.format(self=self)

    def __eq__(self, other):
        return (self.a == other.a) and (self.b == other.b)


class B(object):
    def __init__(self, c, d):
        self.c = c
        self.d = d

    def __repr__(self):
        templ = "<B: c:{self.c} d: {self.c}>"
        return templ.format(self=self)

    def __eq__(self, other):
        return (self.c == other.c) and (self.d == other.d)

File serdeser.py:

import json


def serialize(obj):
    if isinstance(obj, A):
        return json.dumps({"type": "A", "args": {"a": obj.a, "b": obj.b}})
    elif isinstance(obj, B):
        return json.dumps({"type": "B", "args": {"c": obj.c, "d": obj.d}})
    else:
        raise ValueError()


def deserialize(string):
    dct = json.loads(string)
    objtype = dct.get("type")
    if objtype == "A":
        return A(**dct["args"])
    elif objtype == "B":
        return B(**dct["args"])
    else:
        raise ValueError("U 

Post Status

Asked in February 2016
Viewed 2,353 times
Voted 9
Answered 1 times

Search




Leave an answer