我想用 JSON 编码对象。但是,我不知道如何在不转义字符串的情况下进行输出。
import json
class Abc:
def __init__(self):
self.name="abc name"
def toJSON(self):
return json.dumps(self.__dict__, cls=ComplexEncoder)
class Doc:
def __init__(self):
self.abc=Abc()
def toJSON(self):
return json.dumps(self.__dict__, cls=ComplexEncoder)
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Abc) or isinstance(obj, Doc):
return obj.toJSON()
else:
return json.JSONEncoder.default(self, obj)
doc=Doc()
print doc.toJSON()
结果是(转储返回一个字符串表示形式,这就是“被转义的原因)
{"abc": "{\"name\": \"abc name\"}"}
我想要一些不同的东西。预期结果是
{"abc": {"name": "abc name"}"}
但我不知道如何... 有什么提示吗?
提前致谢。
我之前的示例,带有另一个嵌套对象和您的建议:
import json
class Identity:
def __init__(self):
self.name="abc name"
self.first="abc first"
self.addr=Addr()
def reprJSON(self):
return dict(name=self.name, firstname=self.first, address=self.addr)
class Addr:
def __init__(self):
self.street="sesame street"
self.zip="13000"
def reprJSON(self):
return dict(street=self.street, zip=self.zip)
class Doc:
def __init__(self):
self.identity=Identity()
self.data="all data"
def reprJSON(self):
return dict(id=self.identity, data=self.data)
class ComplexEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj,'reprJSON'):
return obj.reprJSON()
else:
return json.JSONEncoder.default(self, obj)
doc=Doc()
print "Str representation"
print doc.reprJSON()
print "Full JSON"
print json.dumps(doc.reprJSON(), cls=ComplexEncoder)
print "Partial JSON"
print json.dumps(doc.identity.addr.reprJSON(), cls=ComplexEncoder)
产生预期结果:
Str representation
{'data': 'all data', 'id': <__main__.Identity instance at 0x1005317e8>}
Full JSON
{"data": "all data", "id": {"name": "abc name", "firstname": "abc first", "address": {"street": "sesame street", "zip": "13000"}}}
Partial JSON
{"street": "sesame street", "zip": "13000"}
谢谢。
因此,眼前的问题是您向 json 模块传递了一个 JSON 值,该值将被编码为 JSON 值中的另一个字符串。
更广泛的问题是你把这个问题搞得太复杂了。
利用 Python 和 JavaScript 之间的 JSON 日期时间,我会选择更接近于此的东西:
import json
class Abc:
def __init__(self):
self.name="abc name"
def jsonable(self):
return self.name
class Doc:
def __init__(self):
self.abc=Abc()
def jsonable(self):
return self.__dict__
def ComplexHandler(Obj):
if hasattr(Obj, 'jsonable'):
return Obj.jsonable()
else:
raise TypeError('Object of type %s with value of %s is not JSON serializable' % (type(Obj), repr(Obj)))
doc=Doc()
print json.dumps(doc, default=ComplexHandler)
这让你:
~$ python nestjson.py
{"abc": "abc name"}
~$
这可以变得更干净/更理智/更安全(特别是,在调试/故障排除之外,通常不建议只抓住
__dict__
),但它应该能够传达要点。从根本上讲,您需要的是一种从树中的每个“节点”中获取 json 兼容对象(无论是简单的字符串或数字,还是列表或字典)的方法。该对象不应该是一个已经 JSON 序列化的对象,而这正是您正在做的。
__iter__()
方法,如下所示。这还允许“jsonize”列表元素、日期时间和小数,无需额外的依赖项,只需使用 dict()。
import datetime
import decimal
class Jsonable(object):
def __iter__(self):
for attr, value in self.__dict__.iteritems():
if isinstance(value, datetime.datetime):
iso = value.isoformat()
yield attr, iso
elif isinstance(value, decimal.Decimal):
yield attr, str(value)
elif(hasattr(value, '__iter__')):
if(hasattr(value, 'pop')):
a = []
for subval in value:
if(hasattr(subval, '__iter__')):
a.append(dict(subval))
else:
a.append(subval)
yield attr, a
else:
yield attr, dict(value)
else:
yield attr, value
class Identity(Jsonable):
def __init__(self):
self.name="abc name"
self.first="abc first"
self.addr=Addr()
class Addr(Jsonable):
def __init__(self):
self.street="sesame street"
self.zip="13000"
class Doc(Jsonable):
def __init__(self):
self.identity=Identity()
self.data="all data"
def main():
doc=Doc()
print "-Dictionary- \n"
print dict(doc)
print "\n-JSON- \n"
print json.dumps(dict(doc), sort_keys=True, indent=4)
if __name__ == '__main__':
main()
输出:
-Dictionary-
{'data': 'all data', 'identity': {'first': 'abc first', 'addr': {'street': 'sesame street', 'zip': '13000'}, 'name': 'abc name'}}
-JSON-
{
"data": "all data",
"identity": {
"addr": {
"street": "sesame street",
"zip": "13000"
},
"first": "abc first",
"name": "abc name"
}
}
希望有帮助! 谢谢
,但目标是仅对嵌套的 python 对象进行编码。 在一篇
文章中,我找到了一个优雅的解决方案,它完全符合您的要求,但没有样板代码。因为您甚至可以免费获得反序列化部分,所以我将首先向您展示您的确切问题的解决方案,然后提供一个更清晰的版本,其中反序列化也可以工作。
您问题的准确解决方案
import json
class Abc(object):
def __init__(self):
self.name = "abc name"
class Doc(object):
def __init__(self):
self.abc = Abc()
doc = Doc()
# Serialization
json_data = json.dumps(doc, default=lambda o: o.__dict__)
print(json_data)
这将准确输出您所要求的内容:
{"abc": {"name": "abc name"}}
import json
class Abc(object):
def __init__(self, name: str):
self.name = name
class Doc(object):
def __init__(self, abc):
self.abc = abc
abc = Abc("abc name")
doc = Doc(abc)
# Serialization
json_data = json.dumps(doc, default=lambda o: o.__dict__)
print(json_data)
# De-serialization
decoded_doc = Doc(**json.loads(json_data))
print(decoded_doc)
print(vars(decoded_doc))
这将输出以下内容:
{"abc": {"name": "abc name"}}
<__main__.Doc object at 0x7ff75366f250>
{'abc': {'name': 'abc name'}}
整个魔法通过定义一个默认的 lambda 函数来实现:
json_data = json.dumps(doc, default=lambda o: o.__dict__)
。
def reprJSON(self):
d = dict()
for a, v in self.__dict__.items():
if (hasattr(v, "reprJSON")):
d[a] = v.reprJSON()
else:
d[a] = v
return d
它可以用于任何具有太繁忙而无法手动编码的子类的对象。或者可以成为所有班级的帮手。这也适用于包含其他类的成员数组的完整 JSON 表示(当然,只要它们实现 reprJSON() )。
,它于 2022 年发布。
pip install jsons
class Person:
name:str
birthday:datetime
personObject = Person("Tony", date_of_birth)
import jsons
json_data = jsons.dumps(personObject, indent=4)