9

リテラル json 文字列を保持できる特別なオブジェクトがあるとします。これは、より大きな JSON オブジェクトのフィールドとして、リテラル値自体 (JSON を含む文字列ではありません) として使用する予定です。

これを実現できるカスタム エンコーダーを書きたいと思います。

> encoder.encode({
>     'a': LiteralJson('{}')
> })
{"a": {}}

JSONEncoder のサブクラス化とデフォルトのオーバーライドがうまくいくとは思えません{"a": "{}"}

LiteralJson が別のディクショナリ内のどこかにネストされている場合、エンコードのオーバーライドも機能しないようです。

興味があれば、これの背景は、JSON でエンコードされた値をキャッシュに保存していることです。そのように動作しますが、これらの値の一部はかなり長く、無駄に見えるだけです。

次のエンコーダーは、私が好きなことを実現します (ただし、不必要に遅いようです)。

class MagicEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, LiteralJson):
            return json.loads(obj.content)
        else:
            return json.JSONEncoder.default(self, obj)
4

2 に答える 2

4

最近、同様の質問があったことに気づきました。答えは、代替トークンを使用することを提案しました。

JSONEncoderランダムな UUID を使用してこれらのトークンを内部で生成するカスタムを使用して、このロジックを多かれ少なかれ透過的に統合することができます。(私が「 」と呼んRawJavaScriptTextでいるものは、あなたの「 」に相当しますLiteralJson。)

その後、直接使用できますjson.dumps(testvar, cls=RawJsJSONEncoder)

import json
import uuid

class RawJavaScriptText:
    def __init__(self, jstext):
        self._jstext = jstext
    def get_jstext(self):
        return self._jstext

class RawJsJSONEncoder(json.JSONEncoder):
    def __init__(self, *args, **kwargs):
        json.JSONEncoder.__init__(self, *args, **kwargs)
        self._replacement_map = {}

    def default(self, o):
        if isinstance(o, RawJavaScriptText):
            key = uuid.uuid4().hex
            self._replacement_map[key] = o.get_jstext()
            return key
        else:
            return json.JSONEncoder.default(self, o)

    def encode(self, o):
        result = json.JSONEncoder.encode(self, o)
        for k, v in self._replacement_map.iteritems():
             result = result.replace('"%s"' % (k,), v)
        return result

testvar = {
   'a': 1,
   'b': 'abc',
   'c': RawJavaScriptText('{ "x": [ 1, 2, 3 ] }')
}

print json.dumps(testvar, cls=RawJsJSONEncoder)

結果 (Python 2.6 および 2.7 を使用):

{"a": 1, "c": { "x": [ 1, 2, 3 ] }, "b": "abc"}
于 2012-11-03T03:59:14.310 に答える