我试图创建一个类实例的JSON字符串表示,有困难。假设这个类是这样构建的:
class testclass:
value1 = "a"
value2 = "b"
对json的调用。转储是这样的:
t = testclass()
json.dumps(t)
它失败了,告诉我测试类不是JSON序列化的。
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
我也尝试过使用pickle模块:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
它提供类实例的信息,而不是类实例的序列化内容。
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
我做错了什么?
这里有两个简单的函数,用于序列化任何不复杂的类,没有前面解释的那么复杂。
我将此用于配置类型的东西,因为我可以向类添加新成员而无需进行代码调整。
import json
class SimpleClass:
def __init__(self, a=None, b=None, c=None):
self.a = a
self.b = b
self.c = c
def serialize_json(instance=None, path=None):
dt = {}
dt.update(vars(instance))
with open(path, "w") as file:
json.dump(dt, file)
def deserialize_json(cls=None, path=None):
def read_json(_path):
with open(_path, "r") as file:
return json.load(file)
data = read_json(path)
instance = object.__new__(cls)
for key, value in data.items():
setattr(instance, key, value)
return instance
# Usage: Create class and serialize under Windows file system.
write_settings = SimpleClass(a=1, b=2, c=3)
serialize_json(write_settings, r"c:\temp\test.json")
# Read back and rehydrate.
read_settings = deserialize_json(SimpleClass, r"c:\temp\test.json")
# results are the same.
print(vars(write_settings))
print(vars(read_settings))
# output:
# {'c': 3, 'b': 2, 'a': 1}
# {'c': 3, 'b': 2, 'a': 1}
我认为,与其像公认的答案中建议的那样继承,不如使用多态。否则你必须有一个大的if else语句来自定义每个对象的编码。这意味着为JSON创建一个通用的默认编码器:
def jsonDefEncoder(obj):
if hasattr(obj, 'jsonEnc'):
return obj.jsonEnc()
else: #some default behavior
return obj.__dict__
然后在你想序列化的每个类中都有一个jsonEnc()函数。如。
class A(object):
def __init__(self,lengthInFeet):
self.lengthInFeet=lengthInFeet
def jsonEnc(self):
return {'lengthInMeters': lengthInFeet * 0.3 } # each foot is 0.3 meter
然后调用json.dumps(classInstance,default=jsonDefEncoder)
这里有一些关于如何开始做这件事的很好的答案。但有一些事情要记住:
如果实例嵌套在大型数据结构中怎么办?
如果还想要类名呢?
如果要反序列化实例该怎么办?
如果你使用__slots__而不是__dict__呢?
如果你只是不想自己动手呢?
json-tricks是一个库(我创建的,其他人贡献的),它已经能够做到这一点很长时间了。例如:
class MyTestCls:
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
cls_instance = MyTestCls(s='ub', dct={'7': 7})
json = dumps(cls_instance, indent=4)
instance = loads(json)
您将得到您的实例。这里的json是这样的:
{
"__instance_type__": [
"json_tricks.test_class",
"MyTestCls"
],
"attributes": {
"s": "ub",
"dct": {
"7": 7
}
}
}
如果你喜欢自己做解决方案,你可以查看json-tricks的源代码,以免忘记一些特殊情况(如__slots__)。
它也可以处理其他类型,比如numpy数组,datetimes,复数;它还允许注释。
有一种方法非常适合我,你可以试试:
Json.dumps()可以接受一个可选参数default,您可以在其中为未知类型指定一个自定义序列化器函数,在我的例子中是这样的
def serialize(obj):
"""JSON serializer for objects not serializable by default json code"""
if isinstance(obj, date):
serial = obj.isoformat()
return serial
if isinstance(obj, time):
serial = obj.isoformat()
return serial
return obj.__dict__
前两个if用于日期和时间序列化
然后有一个obj。为任何其他对象返回__dict__。
最终决定是这样的:
json.dumps(myObj, default=serialize)
当你在序列化一个集合,并且你不想为每个对象显式地调用__dict__时,它特别好。这里是自动完成的。
到目前为止对我来说很好,期待你的想法。
你可以尝试objprint,这是一个轻量级的库,用于打印Python对象,它支持json输出。
pip install objprint
from objprint import objjson
t = testclass()
json_obj = objjson(t)
print(json.dumps(json_obj))
objjson基本上将任意对象转换为jsoniizable对象,如果它不是dict, list等内置类型,则它的原始Python类型有一个特殊的键.type。
如果只是想打印它,可以使用op,它通常用于以人类可读的格式打印对象。
from objprint import op
t = testclass()
op(t, format="json", indent=2)
# If you want to dump to a file
with open("my_obj.json", "w") as f:
# This is the same usage as print
op(t, format="json", file=f)