我有一些序列化和反序列化代码,它们在一个模块中(以及在我关心的类领域(中运行良好。 例如
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 定义此类类以及添加的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
就没有问题在同一模块中定义。