我正在缓存一些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.dumps default
argument的文档,因为它似乎是人们可以解决此问题的地方,并在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}"}'
所需的输出将包括未转义的字符串m.str
,即:
'{"a": {"x": 123}}'
如果json模块没有编码/转义default
参数的返回值,或者如果可以避免相同的话,那将会很好。如果没有通过default
参数的方法,则可能必须通过重载encode
的{{1}}和iterencode
方法来实现此目标,这会带来挑战复杂性,互操作性和性能。
答案 0 :(得分:5)
快速肮脏的方法是修补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]"]
答案 1 :(得分: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)
第三个选项是以非序列化形式缓存item1
和item2
,作为Python结构而不是JSON字符串。
答案 2 :(得分:1)
您可以使用效果更好的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
的所有C优化。