我试图创建一个类实例的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.'
我做错了什么?
我一直在我的Flask应用程序中使用的一种方法,将类实例序列化为JSON响应。
Github项目供参考
from json import JSONEncoder
import json
from typing import List
class ResponseEncoder(JSONEncoder):
def default(self, o):
return o.__dict__
class ListResponse:
def __init__(self, data: List):
self.data = data
self.count = len(data)
class A:
def __init__(self, message: str):
self.message = message
class B:
def __init__(self, record: A):
self.record = record
class C:
def __init__(self, data: B):
self.data = data
现在创建一个A, B, C的实例,然后编码。
data_a = A('Test Data')
data_b = B(data_a)
data_c = C(data_b)
response = ResponseEncoder().encode(data_c)
json_response = json.loads(response)
输出
{
"data": {
"record": {
"message": "Test Data"
}
}
}
对于列表类型响应
records = ['One', 'Two', 'Three']
list_response = ListResponse(records)
response = ResponseEncoder().encode(list_response)
json_response = json.loads(response)
输出
{
"data": [
"One",
"Two",
"Three"
],
"count": 3
}
你可以在json.dumps()函数中指定默认的命名参数:
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)
注意:在这种情况下,您需要实例变量而不是类变量,正如问题中的示例所尝试做的那样。(我假设请求者意味着类实例是类的对象)
我首先从@phihag的回答中了解到这一点。发现这是最简单、最干净的工作方式。
基本的问题是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}
我为此做了一个函数,效果很好:
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)
我只会:
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)