如何使一个Python类序列化?
class FileItem:
def __init__(self, fname):
self.fname = fname
尝试序列化为JSON:
>>> import json
>>> x = FileItem('/foo/bar')
>>> json.dumps(x)
TypeError: Object of type 'FileItem' is not JSON serializable
如何使一个Python类序列化?
class FileItem:
def __init__(self, fname):
self.fname = fname
尝试序列化为JSON:
>>> import json
>>> x = FileItem('/foo/bar')
>>> json.dumps(x)
TypeError: Object of type 'FileItem' is not JSON serializable
当前回答
为了在10年前的火灾中再添加一个日志,我还将为这个任务提供数据类向导,假设您使用的是Python 3.6+。这可以很好地用于数据类,这实际上是3.7+版本的python内置模块。
dataclass-wizard库将把对象(及其所有属性递归地)转换为dict,并使用fromdict使反向(反序列化)非常简单。另外,这里是PyPi链接:https://pypi.org/project/dataclass-wizard/。
import dataclass_wizard
import dataclasses
@dataclasses.dataclass
class A:
hello: str
a_field: int
obj = A('world', 123)
a_dict = dataclass_wizard.asdict(obj)
# {'hello': 'world', 'aField': 123}
或者如果你想要一个字符串:
a_str = jsons.dumps(dataclass_wizard.asdict(obj))
或者您的类是否从dataclass_wizard扩展。JSONWizard:
a_str = your_object.to_json()
最后,标准库还支持Union类型的数据类,这基本上意味着可以将dict反序列化为类C1或C2的对象。例如:
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class Outer(JSONWizard):
class _(JSONWizard.Meta):
tag_key = 'tag'
auto_assign_tags = True
my_string: str
inner: 'A | B' # alternate syntax: `inner: typing.Union['A', 'B']`
@dataclass
class A:
my_field: int
@dataclass
class B:
my_field: str
my_dict = {'myString': 'test', 'inner': {'tag': 'B', 'myField': 'test'}}
obj = Outer.from_dict(my_dict)
# True
assert repr(obj) == "Outer(my_string='test', inner=B(my_field='test'))"
obj.to_json()
# {"myString": "test", "inner": {"myField": "test", "tag": "B"}}
其他回答
为了在10年前的火灾中再添加一个日志,我还将为这个任务提供数据类向导,假设您使用的是Python 3.6+。这可以很好地用于数据类,这实际上是3.7+版本的python内置模块。
dataclass-wizard库将把对象(及其所有属性递归地)转换为dict,并使用fromdict使反向(反序列化)非常简单。另外,这里是PyPi链接:https://pypi.org/project/dataclass-wizard/。
import dataclass_wizard
import dataclasses
@dataclasses.dataclass
class A:
hello: str
a_field: int
obj = A('world', 123)
a_dict = dataclass_wizard.asdict(obj)
# {'hello': 'world', 'aField': 123}
或者如果你想要一个字符串:
a_str = jsons.dumps(dataclass_wizard.asdict(obj))
或者您的类是否从dataclass_wizard扩展。JSONWizard:
a_str = your_object.to_json()
最后,标准库还支持Union类型的数据类,这基本上意味着可以将dict反序列化为类C1或C2的对象。例如:
from dataclasses import dataclass
from dataclass_wizard import JSONWizard
@dataclass
class Outer(JSONWizard):
class _(JSONWizard.Meta):
tag_key = 'tag'
auto_assign_tags = True
my_string: str
inner: 'A | B' # alternate syntax: `inner: typing.Union['A', 'B']`
@dataclass
class A:
my_field: int
@dataclass
class B:
my_field: str
my_dict = {'myString': 'test', 'inner': {'tag': 'B', 'myField': 'test'}}
obj = Outer.from_dict(my_dict)
# True
assert repr(obj) == "Outer(my_string='test', inner=B(my_field='test'))"
obj.to_json()
# {"myString": "test", "inner": {"myField": "test", "tag": "B"}}
我喜欢Onur的答案,但会扩展到包括一个可选的toJSON()方法,用于对象序列化自己:
def dumper(obj):
try:
return obj.toJSON()
except:
return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)
Json在它可以打印的对象方面受到限制,而jsonpickle(你可能需要一个PIP安装jsonpickle)在它不能缩进文本方面受到限制。如果你想检查一个你不能改变类的对象的内容,我仍然找不到比:
import json
import jsonpickle
...
print json.dumps(json.loads(jsonpickle.encode(object)), indent=2)
注意:他们仍然不能打印对象方法。
要添加另一个选项:您可以使用attrs包和asdict方法。
class ObjectEncoder(JSONEncoder):
def default(self, o):
return attr.asdict(o)
json.dumps(objects, cls=ObjectEncoder)
然后再转换回去
def from_json(o):
if '_obj_name' in o:
type_ = o['_obj_name']
del o['_obj_name']
return globals()[type_](**o)
else:
return o
data = JSONDecoder(object_hook=from_json).decode(data)
类看起来像这样
@attr.s
class Foo(object):
x = attr.ib()
_obj_name = attr.ib(init=False, default='Foo')
如果你能够安装一个软件包,我建议你试试dill,它在我的项目中工作得很好。这个包的一个优点是它具有与pickle相同的接口,因此如果您已经在项目中使用了pickle,则可以简单地替换为dill并查看脚本是否运行,而无需更改任何代码。所以这是一个非常便宜的解决方案!
(完全反披露:我与莳萝项目没有任何关联,也从未参与过。)
安装包:
pip install dill
然后编辑你的代码导入莳萝而不是pickle:
# import pickle
import dill as pickle
运行脚本,看看它是否有效。(如果是的话,你可能想要清理你的代码,这样你就不再隐藏pickle模块的名字了!)
关于dill可以和不能序列化的数据类型的一些细节,来自项目页面:
dill can pickle the following standard types: none, type, bool, int, long, float, complex, str, unicode, tuple, list, dict, file, buffer, builtin, both old and new style classes, instances of old and new style classes, set, frozenset, array, functions, exceptions dill can also pickle more ‘exotic’ standard types: functions with yields, nested functions, lambdas, cell, method, unboundmethod, module, code, methodwrapper, dictproxy, methoddescriptor, getsetdescriptor, memberdescriptor, wrapperdescriptor, xrange, slice, notimplemented, ellipsis, quit dill cannot yet pickle these standard types: frame, generator, traceback