将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} 

上述方法在本博客文章中进行了讨论:

http://www.marcstober.com/blog/2007/07/07/serializing-arbitrary-python-objects-to-json-using-__dict__/

注意:我已经编辑了这个答案。 原始版本只讨论了.__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模块,这是一个有趣的混合方法。

https://github.com/jsonpickle/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)

注意:在这种情况下,您需要instancevariables而不是classvariables,如问题中的示例所尝试的那样。 (我假设提问者意味着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}