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値の別の文字列としてエンコードされます。
より広範な問題は、これを非常に複雑にしていることです。
JSON datetime between PythonとJavaScript で描画します。これに近いものを使用します。
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互換オブジェクト(単純な文字列または数字、またはリストまたは辞書)を取得する方法です。そのオブジェクトはnotであり、既にJSONでシリアル化されているオブジェクトである必要があります。
Fred Laurentの答えのようなコードの繰り返しを避けるために、次のように__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"
}
}
それが役に立てば幸い!ありがとう
これをコメントとして追加し、回答として追加することはできませんでした。フレッドの最後のサンプルは私にとって有用でした。jsonpickleはこれを行うと言われましたが、モジュールを正しくインストールして実行することができませんでした。ここでコードを使用しました。マイナーな微調整ですが、いくつかのオブジェクトに手動で追加するには変数が多すぎます。それで、この小さなループは物事を単純化しました:
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()を実装している限り)。
これはあなたが探しているものです: https://github.com/jsonpickle/jsonpickle
Pythonオブジェクトのネストされたシリアル化を行い、カスタムタイプをシリアル化するために簡単に拡張できます。