如何使 Python 反序列化函数可从另一个模块使用



我有一些序列化和反序列化代码,它们在一个模块中(以及在我关心的类领域(中运行良好。 例如

class A(...):
    ...
class B(...):
    ...
def serialize( obj ):
    ...
def deserialize( string ):
    ...
assert( obj == deserialize( serialize( obj ) ) )

但是,如果我在另一个模块中定义一个类并导入serialize并在那里deserialize,序列化有效,但我在反序列化方面遇到了问题。 反序列化函数不"知道"其他模块中的类定义,也无法实例化实例。

到目前为止,我已经使用了两种不同的方法来解决这个问题。 一种是通过传递globals()locals()进入deserialize然后与他们一起调用eval。 另一个有呼叫者通过__name__deserialize呼叫inspect.getmembers( sys.modules[ passedInName ] )。 我还可能需要在deserialize可见的某个列表中注册每个可序列化类。

但是,我不喜欢任何这些解决方法。 有没有更好的方法?

(如果重要的话,我需要使用 Python 2.7,因为这是我们在工作时所拥有的。

补充:我已经根据ABCMeta元类编写了一个版本的"在某个列表中注册每个可序列化类"策略,这似乎不太可怕。 它确实涉及查看感觉有点不对的_abc_registry

一个问题可能出现在你上次的测试中:

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

对象将"实际上相等",但将有两个不同的实例类,所有成员都相同。

您可以通过向对象询问id(obj)值来检查它,您将获得不同的值。

要解决这个问题(如果您想允许两个不同的实例相等(是将__eq__添加到您的类。

这是我尝试使用 JSON 定义此类类以及添加的serializedeserialize字符串。为了表明,serializedeserialize函数可能存在于类以外的其他模块中,它们被放入不同的模块中:

文件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)

文件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("Unknown type of data")

测试代码:test_ser.py

这是我的测试(使用 pytest (。我把它放在文件test_ser.py

import pytest

@pytest.fixture
def a_instance():
    from serdeser import A
    return A(11, 12)

@pytest.fixture
def a_serialized(a_instance):
    from serdeser import serialize
    return serialize(a_instance)

@pytest.fixture
def b_instance():
    from serdeser import B
    return B(88, 99)

@pytest.fixture
def b_serialized(b_instance):
    from serdeser import serialize
    return serialize(b_instance)

def test_A(a_instance, a_serialized):
    from serdeser import deserialize
    assert a_instance == deserialize(a_serialized)

def test_B(b_instance, b_serialized):
    from serdeser import deserialize
    assert b_instance == deserialize(b_serialized)

您应已安装pytest

$ pip install pytest

运行测试(并假设文件serdeser.pyclassroom.py位于同一目录:

$ py.test -sv test_ser.py                                                              (env: stack) 
========================================= test session starts =========================================
platform linux2 -- Python 2.7.9 -- py-1.4.30 -- pytest-2.7.2 -- /home/javl/.virtualenvs/stack/bin/python2
rootdir: /home/javl/sandbox/stack, inifile: 
collected 2 items 
test_ser.py::test_A PASSED
test_ser.py::test_B PASSED
====================================== 2 passed in 0.01 seconds =======================================

一切都在流逝给我。

如果在从当前目录导入serdeser模块时遇到问题,请使用:

$ EXPORT PYTHONPATH="."

在我的测试中,我从不将任何内容从serdeser导入全局范围,只导入到测试用例的范围功能。

导入功能deserialize了解类A就没有问题在同一模块中定义。

最新更新