我试图创建一个类实例的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}
这可以用pydantic轻松处理,因为它已经内置了这个功能。
选项1:正常方式
from pydantic import BaseModel
class testclass(BaseModel):
value1: str = "a"
value2: str = "b"
test = testclass()
>>> print(test.json(indent=4))
{
"value1": "a",
"value2": "b"
}
选项2:使用pydantic的数据类
import json
from pydantic.dataclasses import dataclass
from pydantic.json import pydantic_encoder
@dataclass
class testclass:
value1: str = "a"
value2: str = "b"
test = testclass()
>>> print(json.dumps(test, indent=4, default=pydantic_encoder))
{
"value1": "a",
"value2": "b"
}
我为此做了一个函数,效果很好:
def serialize(x,*args,**kwargs):
kwargs.setdefault('default',lambda x:getattr(x,'__dict__',dict((k,getattr(x,k) if not callable(getattr(x,k)) else repr(getattr(x,k))) for k in dir(x) if not (k.startswith('__') or isinstance(getattr(x,k),x.__class__)))))
return json.dumps(x,*args,**kwargs)
基本的问题是JSON编码器JSON .dumps()默认情况下只知道如何序列化有限的对象类型集,所有的内置类型。名单在这里:https://docs.python.org/3.3/library/json.html#encoders-and-decoders
一个好的解决方案是让您的类继承自JSONEncoder,然后实现JSONEncoder.default()函数,并使该函数为您的类发出正确的JSON。
一个简单的解决方案是在该实例的.__dict__成员上调用json.dumps()。这是一个标准的Python字典,如果你的类很简单,它将是JSON序列化的。
class Foo(object):
def __init__(self):
self.x = 1
self.y = 2
foo = Foo()
s = json.dumps(foo) # raises TypeError with "is not JSON serializable"
s = json.dumps(foo.__dict__) # s set to: {"x":1, "y":2}
上述方法在这篇博文中进行了讨论:
使用_dict_将任意Python对象序列化为JSON
当然,Python提供了一个内置函数,为您访问.__dict__,称为vars()。
所以上面的例子也可以这样做:
s = json.dumps(vars(foo)) # s set to: {"x":1, "y":2}