5

我正在缓存一些 JSON 数据,并在存储中表示为 JSON 编码字符串。在将 JSON 发送到客户端之前,服务器不会对 JSON 执行任何操作,除了整理多个缓存对象,如下所示:

def get_cached_items():
  item1 = cache.get(1)
  item2 = cache.get(2)
  return json.dumps(item1=item1, item2=item2, msg="123")

返回值中可能包含其他项目,在这种情况下由 表示msg="123"

问题是缓存的项目是双重转义的。图书馆理应允许通过字符串而不转义它。

我查看了json.dumpsdefault参数的文档,因为它似乎是一个可以解决这个问题的地方,并在 google/SO 上搜索但没有发现有用的结果。

从性能的角度来看,如果我必须解码每个缓存项目的 JSON 以将其发送到浏览器,那将是不幸的。从复杂性的角度来看,如果不能使用json.dumps.

我倾向于编写一个存储缓存字符串的类,当default处理程序遇到此类的实例时,它会使用该字符串而不执行转义。不过,我还没有弄清楚如何实现这一目标,我将不胜感激您的想法和帮助。

编辑为清楚起见,这里是建议default技术的一个例子:

class RawJSON(object):
   def __init__(self, str):
       self.str = str

class JSONEncoderWithRaw(json.JSONEncoder):
   def default(self, o):
       if isinstance(o, RawJSON): 
          return o.str # but avoid call to `encode_basestring` (or ASCII equiv.)
       return super(JSONEncoderWithRaw, self).default(o)

这是上述的退化示例:

>>> class M():
       str = ''
>>> m = M()
>>> m.str = json.dumps(dict(x=123))
>>> json.dumps(dict(a=m), default=lambda (o): o.str)
'{"a": "{\\"x\\": 123}"}'

所需的输出将包括未转义的 string m.str,即:

'{"a": {"x": 123}}'

如果 json 模块没有对default参数的返回进行编码/转义,或者可以避免同样的情况,那就太好了。在没有通过default参数的方法的情况下,这里可能不得不通过重载 的encodeiterencode方法来达到目的JSONEncoder,这在复杂性、互操作性和性能方面带来了挑战。

4

3 回答 3

6

一种快速的方法是修补json.encoder.encode_basestring*()函数:

import json

class RawJson(unicode):
    pass

# patch json.encoder module
for name in ['encode_basestring', 'encode_basestring_ascii']:
    def encode(o, _encode=getattr(json.encoder, name)):
        return o if isinstance(o, RawJson) else _encode(o)
    setattr(json.encoder, name, encode)


print(json.dumps([1, RawJson(u'["abc", 2]'), u'["def", 3]']))
# -> [1, ["abc", 2], "[\"def\", 3]"]
于 2013-05-09T19:18:05.573 回答
3

如果要缓存 JSON 字符串,则需要先将它们解码为 python 结构;无法json.dumps()区分普通字符串和真正是 JSON 编码结构的字符串:

return json.dumps({'item1': json.loads(item1), 'item2': json.loads(item2), 'msg': "123"})

不幸的是,没有选项可以在其中包含已经转换的 JSON 数据;该default函数应返回Python值。您从传入的任何对象中提取数据并返回一个可以转换为 JSON 的值,而不是一个本身已经是 JSON 的值。

我能看到的唯一另一种方法是插入“模板”值,然后使用字符串替换技术来操作 JSON 输出,用您的实际缓存数据替换模板:

json_data = json.dumps({'item1': '==item1==', 'item2': '==item2==', 'msg': "123"})
return json_data.replace('"==item1=="', item1).replace('"==item2=="', item2)

第三种选择是以非序列化形式缓存,作为 Python 结构而不是 JSON 字符串item1item2

于 2013-05-09T15:20:28.230 回答
2

您可以使用更好维护simplejson的而不是json提供此功能的。

import simplejson as json
from simplejson.encoder import RawJSON

print(json.dumps([1, RawJSON(u'["abc", 2]'), u'["def", 3]']))
# -> [1, ["abc", 2], "[\"def\", 3]"]

您可以获得简单的代码,以及simplejson.

于 2017-07-04T23:19:56.220 回答