如何使一个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
当前回答
TLDR:复制-粘贴下面的选项1或选项2
真正的/完整的答案:让Pythons json模块与你的类一起工作
AKA,求解:json。dump ({"thing": YOUR_CLASS()})
解释:
Yes, a good reliable solution exists No, there is no python "official" solution By official solution, I mean there is no way (as of 2023) to add a method to your class (like toJSON in JavaScript) and/or no way to register your class with the built-in json module. When something like json.dumps([1,2, your_obj]) is executed, python doesn't check a lookup table or object method. I'm not sure why other answers don't explain this The closest official approach is probably andyhasit's answer which is to inherit from a dictionary. However, inheriting from a dictionary doesn't work very well for many custom classes like AdvancedDateTime, or pytorch tensors. The ideal workaround is this: Mutate json.dumps (affects everywhere, even pip modules that import json) Add def __json__(self) method to your class
选项1:让一个模块来做补丁
PIP安装json-fix (扩展+包装版FancyJohn的回答,谢谢@FancyJohn)
your_class_definition.py
import json_fix
class YOUR_CLASS:
def __json__(self):
# YOUR CUSTOM CODE HERE
# you probably just want to do:
# return self.__dict__
return "a built-in object that is naturally json-able"
这是它。
使用示例:
from your_class_definition import YOUR_CLASS
import json
json.dumps([1,2, YOUR_CLASS()], indent=0)
# '[\n1,\n2,\n"a built-in object that is naturally json-able"\n]'
生成json。dump适用于Numpy数组,Pandas DataFrames和其他第三方对象,请参阅模块(只有大约2行代码,但需要解释)。
它是如何工作的?嗯…
选项2:补丁json。把你自己
注意:这种方法是简化的,它在已知的edgcase上失败(例如:如果你的自定义类继承了dict或其他内置类),并且它错过了控制外部类的json行为(numpy数组,datetime, dataframes,张量等)。
some_file_thats_imported_before_your_class_definitions.py
# Step: 1
# create the patch
from json import JSONEncoder
def wrapped_default(self, obj):
return getattr(obj.__class__, "__json__", wrapped_default.default)(obj)
wrapped_default.default = JSONEncoder().default
# apply the patch
JSONEncoder.original_default = JSONEncoder.default
JSONEncoder.default = wrapped_default
your_class_definition.py
# Step 2
class YOUR_CLASS:
def __json__(self, **options):
# YOUR CUSTOM CODE HERE
# you probably just want to do:
# return self.__dict__
return "a built-in object that is natually json-able"
_
其他答案似乎都是“序列化自定义对象的最佳实践/方法”
在这里的文档中已经介绍过了(搜索“complex”可以找到编码复数的例子)
其他回答
只需要像这样添加to_json方法到你的类中:
def to_json(self):
return self.message # or how you want it to be serialized
然后将这段代码(来自这个答案)添加到所有内容的顶部:
from json import JSONEncoder
def _default(self, obj):
return getattr(obj.__class__, "to_json", _default.default)(obj)
_default.default = JSONEncoder().default
JSONEncoder.default = _default
这将会在导入json模块时monkey-patch,所以 JSONEncoder.default()自动检查特殊的to_json() 方法,并使用它对找到的对象进行编码。
就像Onur说的,但是这次你不需要更新项目中的每个json.dumps()。
要添加另一个选项:您可以使用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')
这对我来说很有效:
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))
我最喜欢Lost Koder的方法。当我试图序列化成员/方法不可序列化的更复杂的对象时,我遇到了问题。这是我的实现,工作在更多的对象:
class Serializer(object):
@staticmethod
def serialize(obj):
def check(o):
for k, v in o.__dict__.items():
try:
_ = json.dumps(v)
o.__dict__[k] = v
except TypeError:
o.__dict__[k] = str(v)
return o
return json.dumps(check(obj).__dict__, indent=2)
TLDR:复制-粘贴下面的选项1或选项2
真正的/完整的答案:让Pythons json模块与你的类一起工作
AKA,求解:json。dump ({"thing": YOUR_CLASS()})
解释:
Yes, a good reliable solution exists No, there is no python "official" solution By official solution, I mean there is no way (as of 2023) to add a method to your class (like toJSON in JavaScript) and/or no way to register your class with the built-in json module. When something like json.dumps([1,2, your_obj]) is executed, python doesn't check a lookup table or object method. I'm not sure why other answers don't explain this The closest official approach is probably andyhasit's answer which is to inherit from a dictionary. However, inheriting from a dictionary doesn't work very well for many custom classes like AdvancedDateTime, or pytorch tensors. The ideal workaround is this: Mutate json.dumps (affects everywhere, even pip modules that import json) Add def __json__(self) method to your class
选项1:让一个模块来做补丁
PIP安装json-fix (扩展+包装版FancyJohn的回答,谢谢@FancyJohn)
your_class_definition.py
import json_fix
class YOUR_CLASS:
def __json__(self):
# YOUR CUSTOM CODE HERE
# you probably just want to do:
# return self.__dict__
return "a built-in object that is naturally json-able"
这是它。
使用示例:
from your_class_definition import YOUR_CLASS
import json
json.dumps([1,2, YOUR_CLASS()], indent=0)
# '[\n1,\n2,\n"a built-in object that is naturally json-able"\n]'
生成json。dump适用于Numpy数组,Pandas DataFrames和其他第三方对象,请参阅模块(只有大约2行代码,但需要解释)。
它是如何工作的?嗯…
选项2:补丁json。把你自己
注意:这种方法是简化的,它在已知的edgcase上失败(例如:如果你的自定义类继承了dict或其他内置类),并且它错过了控制外部类的json行为(numpy数组,datetime, dataframes,张量等)。
some_file_thats_imported_before_your_class_definitions.py
# Step: 1
# create the patch
from json import JSONEncoder
def wrapped_default(self, obj):
return getattr(obj.__class__, "__json__", wrapped_default.default)(obj)
wrapped_default.default = JSONEncoder().default
# apply the patch
JSONEncoder.original_default = JSONEncoder.default
JSONEncoder.default = wrapped_default
your_class_definition.py
# Step 2
class YOUR_CLASS:
def __json__(self, **options):
# YOUR CUSTOM CODE HERE
# you probably just want to do:
# return self.__dict__
return "a built-in object that is natually json-able"
_
其他答案似乎都是“序列化自定义对象的最佳实践/方法”
在这里的文档中已经介绍过了(搜索“complex”可以找到编码复数的例子)