将python对象实例序列化为JSON
我想创build一个类实例的JSONstring表示,并有困难。 假设这个类是这样构build的:
class testclass: value1 = "a" value2 = "b"
调用json.dumps是这样的:
t = testclass() json.dumps(t)
这是失败告诉我,testing类不是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.'
我究竟做错了什么?
基本的问题是,JSON编码器json.dumps()
只知道如何序列化一组有限的对象types,默认情况下,所有内置的types。 此处列出: https : //docs.python.org/3.3/library/json.html#encoders-and-decoders
一个好的解决scheme是让你的类inheritance自JSONEncoder
,然后实现JSONEncoder.default()
函数,并使该函数为你的类发出正确的JSON。
一个简单的解决scheme是在该实例的.__dict__
成员上调用json.dumps()
。 这是一个标准的Python dict
,如果你的类是简单的,它将是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__
序列化方法。
我只是做:
data=json.dumps(myobject.__dict__)
这不是完整的答案,如果你有某种复杂的对象类,你肯定不会得到所有的东西。 但是,我用这个为我的一些简单的对象。
一个它能够很好地工作的是从OptionParser模块获得的“options”类。 这里是JSON请求本身。
def executeJson(self, url, options): data=json.dumps(options.__dict__) if options.verbose: print data headers = {'Content-type': 'application/json', 'Accept': 'text/plain'} return requests.post(url, data, headers=headers)
有一种方法对我很好,你可以尝试一下:
json.dumps()
可以采用一个可选的参数default ,你可以为未知的types指定一个自定义的序列化器函数,在我的情况下看起来像
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是date和时间序列化,然后是一个obj.__dict__
返回任何其他对象。
最后的电话看起来像:
json.dumps(myObj, default=serialize)
当你序列化一个集合,而且你不想明确地为每个对象调用__dict__
时,这是特别好的。 这里是自动完成的。
到目前为止,我工作得很好,期待着你的想法。
JSON并不是用来序列化任意Python对象的。 对于dict
对象的序列化来说很好,但是一般来说, pickle
模块就是你应该使用的。 pickle
输出不是真正的人类可读的,但它应该unpickle就好了。 如果你坚持使用JSON,你可以看看jsonpickle
模块,这是一个有趣的混合方法。
使用jsonpickle
import jsonpickle object = YourClass() json_object = jsonpickle.encode(object)
您可以在json.dumps()
函数中指定default
命名参数:
json.dumps(obj, default=lambda x: x.__dict__)
说明:
形成文档( 2.7,3.6 ):
``default(obj)`` is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError.
(适用于Python 2.7和Python 3.x)
注意:在这种情况下,您需要instance
variables而不是class
variables,如问题中的示例所尝试的那样。 (我假设提问者意味着class instance
是一个类的对象)
我首先从@ phihag的回答中了解到了这一点 。 发现它是做这个工作最简单,最干净的方式。
我相信,而不是像接受的答案中所build议的继承,最好是使用多态。 否则,你必须有一个很大的if语句来定制每个对象的编码。 这意味着为JSON创build一个通用的默认编码器:
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 } } }
如果你喜欢自己的解决scheme,你可以看看json-tricks
的来源,以免忘记一些特殊情况(如__slots__
)。
它也有其他types,如numpy数组,date时间,复数; 它也允许评论。
这里有两个简单的函数用于序列化任何非复杂的类,正如前面所解释的那样。
我使用这个configurationtypes的东西,因为我可以添加新的成员的类没有代码的调整。
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}