本文介绍了带有预计算文字JSON的Python中的自定义JSON编码器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑到我有一个特殊的对象,它可能包含一个文字json字符串,我打算将其用作较大的JSON对象中的字段,作为文字值本身(不是包含JSON的字符串).

Consider I have a special object which may hold a literal json string, that I intend to use as a field in a larger JSON object, as the literal value itself (not a string containing the JSON).

我想编写一个可以完成此任务的自定义编码器,即:

I want to write a custom encoder that can accomplish this, ie:

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

我不认为子类化JSONEncoder和覆盖默认值是可行的,因为在最好的情况下,我可以返回字符串,这将使结果为{"a": "{}"}.

I don't believe subclassing JSONEncoder and overriding default will work, because at best there, I can return the string, which would make the result {"a": "{}"}.

当LiteralJson嵌套在另一本词典中的某个位置时,覆盖编码似乎也不起作用.

Overriding encode also appears not to work when the LiteralJson is nested somewhere inside another dictionary.

如果您感兴趣的话,它的背景是我将JSON编码的值存储在缓存中,在我看来,反序列化然后一直重新序列化是一种浪费.这样做是可行的,但是其中一些值相当长,似乎是一个巨大的浪费.

The background for this, if you are interested, is that I am storing JSON-encoded values in a cache, and it seems to me to be a waste to deserialize then reserialize all the time. It works that way, but some of these values are fairly long and it just seems like a huge waste.

以下编码器可以完成我喜欢的操作(但似乎不必要地慢):

The following encoder would accomplish what I like (but seems unnecessarily slow):

class MagicEncoder(json.JSONEncoder):

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

推荐答案

我刚刚意识到我有一个类似的问题最近.答案建议使用替换令牌.

I've just realised I had a similar question recently. The answer suggested to use a replacement token.

可以使用自定义JSONEncoder或多或少透明地集成此逻辑,该自定义JSONEncoder使用一个随机UUID在内部生成这些令牌. (我所说的"RawJavaScriptText"相当于您的"LiteralJson".)

It's possible to integrate this logic more or less transparently using a custom JSONEncoder that generates these tokens internally using a random UUID. (What I've called "RawJavaScriptText" is the equivalent of your "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):

Result (using Python 2.6 and 2.7):

{"a": 1, "c": { "x": [ 1, 2, 3 ] }, "b": "abc"}

这篇关于带有预计算文字JSON的Python中的自定义JSON编码器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 11:24
查看更多