如何使一个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
当前回答
为了给这场11年的大火再添一根柴,我想要一个满足以下条件的解决方案:
只允许使用json.dumps(obj)序列化类FileItem的实例 允许FileItem实例具有属性:FileItem .fname 允许FileItem实例提供给任何库,使用json.dumps(obj)序列化它 不需要将任何其他字段传递给json。转储(如自定义序列化器)
IE:
fileItem = FileItem('filename.ext')
assert json.dumps(fileItem) == '{"fname": "filename.ext"}'
assert fileItem.fname == 'filename.ext'
我的解决方案是:
obj的类是否继承自dict 将每个对象属性映射到底层字典
class FileItem(dict):
def __init__(self, fname):
self['fname'] = fname
#fname property
fname: str = property()
@fname.getter
def fname(self):
return self['fname']
@fname.setter
def fname(self, value: str):
self['fname'] = value
#Repeat for other properties
是的,如果你有很多属性,这有点冗长,但它是JSONSerializable,它的行为像一个对象,你可以把它给任何库,去json.dumps(obj)它。
其他回答
如果你正在使用Python3.5+,你可以使用jsons。(PyPi: https://pypi.org/project/jsons/)它将把你的对象(及其所有属性递归地)转换为字典。
import jsons
a_dict = jsons.dump(your_object)
或者如果你想要一个字符串:
a_str = jsons.dumps(your_object)
或者你的类实现了jsons。JsonSerializable:
a_dict = your_object.json
import json
class Foo(object):
def __init__(self):
self.bar = 'baz'
self._qux = 'flub'
def somemethod(self):
pass
def default(instance):
return {k: v
for k, v in vars(instance).items()
if not str(k).startswith('_')}
json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo
print(json_foo)
这对我来说很有效:
class JsonSerializable(object):
def serialize(self):
return json.dumps(self.__dict__)
def __repr__(self):
return self.serialize()
@staticmethod
def dumper(obj):
if "serialize" in dir(obj):
return obj.serialize()
return obj.__dict__
然后
class FileItem(JsonSerializable):
...
and
log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))
加拉科给出了一个非常简洁的答案。我需要修复一些小的东西,但这是有效的:
Code
# Your custom class
class MyCustom(object):
def __json__(self):
return {
'a': self.a,
'b': self.b,
'__python__': 'mymodule.submodule:MyCustom.from_json',
}
to_json = __json__ # supported by simplejson
@classmethod
def from_json(cls, json):
obj = cls()
obj.a = json['a']
obj.b = json['b']
return obj
# Dumping and loading
import simplejson
obj = MyCustom()
obj.a = 3
obj.b = 4
json = simplejson.dumps(obj, for_json=True)
# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)
# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__
注意,加载需要两个步骤。现在是__python__属性 未使用。
这种情况有多普遍?
使用AlJohri的方法,我检查了流行的方法:
序列化(Python -> JSON):
To_json: 266,595 on 2018-06-27 toJSON: 96,307 on 2018-06-27 __json__: 8504 on 2018-06-27 For_json: 6937 on 2018-06-27
反序列化(JSON -> Python):
From_json: 226,101 on 2018-06-27
Jsonweb似乎是我的最佳解决方案。参见http://www.jsonweb.info/en/latest/
from jsonweb.encode import to_object, dumper
@to_object()
class DataModel(object):
def __init__(self, id, value):
self.id = id
self.value = value
>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'