我有一些序列化和反序列化代码,它们在一个模块中很好地工作(并且在我关心的类的范围内)。 E.g。
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,因为这是我们工作的原因。)
ADDED:我已经编写了一个版本的"注册某些列表中的每个可序列化类"基于ABCMeta
元类的策略似乎并不太可怕。它确实涉及查看感觉有点不对的_abc_registry
。
答案 0 :(得分:0)
最后一次测试可能存在一个问题:
assert( obj == deserialize( serialize( obj ) ) )
对象将实际上相等"但是会有两个不同的实例 所有成员都一样。
您可以通过询问id(obj)
值的对象来检查它,您将获得不同的值。
要解决此问题(如果您希望允许两个不同的实例相同),请将__eq__
添加到您的
类。
我尝试使用JSON定义此类以及添加serialize
和deserialize
串。要表明,serialize
和deserialize
函数可能存在于类之外的其他模块中,
它们被放入不同的模块中:
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.py
和classroom.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
应该没有问题
在同一模块中定义。