python – 如何覆盖JSONEncoder的二进制数据行为?
我在
Python 2.7.10中工作,我有一些二进制数据:
binary_data = b'x01x03x00x00 xe6x10x00x00x01x00x00x00x05x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00' (如果你真的很好奇,那就是几何的Extended WKB.) 实际上,我在dict中的某个地方有这些数据: my_data = { 'something1': 5.5,'something2': u'Some info','something3': b'x01x03x00x00 xe6x10x00x00x01x00x00x00x05x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00xf0?x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00',} 我想将其序列化为JSON来存储它.问题是我收到错误,因为json错误地尝试将其解释为UTF-8: >>> json.dumps(my_data) Traceback (most recent call last): File "<input>",line 1,in <module> File "C:Python27Libjson__init__.py",line 243,in dumps return _default_encoder.encode(obj) File "C:Python27Libjsonencoder.py",line 207,in encode chunks = self.iterencode(o,_one_shot=True) File "C:Python27Libjsonencoder.py",line 270,in iterencode return _iterencode(o,0) UnicodeDecodeError: 'utf8' codec can't decode byte 0xe6 in position 5: invalid continuation byte 我可以手动编码: my_serializable_data = dict(my_data.items()) my_serializable_data['something3'] = binascii.b2a_base64(my_serializable_data['something3']) json.dumps(my_serializable_data) 给了一个很好的 '{"something2": "Some info","something3": "AQMAACDmEAAAAQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==n","something1": 5.5}' 但这很麻烦,因为我需要在整个应用程序中重做这个.我宁愿为这个二进制文件定制json的行为.通常,您可以通过重写JSONEncoder.default来告知json如何序列化某些内容,如下所示: class MyJsonEncoder(json.JSONEncoder): def default(self,o): if isinstance(o,str): return binascii.b2a_base64(o) return super(MyJsonEncoder,self).default(o) 但这没有任何效果,大概是因为str的处理被硬编码到JSONEncoder中: >>> json.dumps(my_data,cls=MyJsonEncoder) Traceback (most recent call last): File "<input>",line 250,in dumps sort_keys=sort_keys,**kw).encode(obj) File "C:Python27Libjsonencoder.py",0) UnicodeDecodeError: 'utf8' codec can't decode byte 0xe6 in position 5: invalid continuation byte 重写JSONEncoder.encode应该可以工作,但我需要从内置库中重建大量逻辑,因为该方法知道如何深入挖掘任意级别以及列表和dicts的组合.我宁愿不这样做;它会很快变得难看并且容易出错. (另外,查看源代码,看起来逻辑可能在json中的模块的全局方法中,这使得这个想法更加混乱.) 这里一个重要的注意事项是,将其反序列化以供以后使用对于这种情况不是问题.这是用于记录目的;当这些数据被反序列化时,它将由开发人员查看.如果他们真的需要对数据做些什么,他们可以手动解码它就好了.我也愿意做出这样的交易:如果某些文本作为str而不是unicode出现,那么无论如何都会得到base64编码. (或者,如果它包含除可打印ASCII之外的任何字符,我可能会修改我的代码只对base64进行编码,但在我能解决我在这里问的问题之前,我甚至无法做出决定.) 那么如何在不尝试重建太多JSONEncoding的情况下覆盖此行为? 解决方法
你真的不需要重建一切本身.一个便宜的出路是做你建议的并覆盖编码,但用清理后的数据构造一个新的dict.
但是,如果您希望灵活地处理二进制数据的任意输入而不必重新实现所有内容,您可以选择在json.encoder模块中修补几个函数.这样做的受控方式是使用特定的编码器来确保默认行为不受影响. import json import json.encoder import binascii _default_encode_basestring = json.encoder.encode_basestring _default_encode_basestring_ascii = json.encoder.encode_basestring_ascii def _check_string(s): if isinstance(s,str): try: s.decode('utf8') except UnicodeDecodeError: return False return True def _encode_basestring(s): if not _check_string(s): s = binascii.b2a_base64(s) return _default_encode_basestring(s) def _encode_basestring_ascii(s): if not _check_string(s): s = binascii.b2a_base64(s) return _default_encode_basestring_ascii(s) class MyJsonEncoder(json.JSONEncoder): def encode(self,o): json.encoder.encode_basestring = _encode_basestring json.encoder.encode_basestring_ascii = _encode_basestring_ascii result = super(MyJsonEncoder,self).encode(o) json.encoder.encode_basestring = _default_encode_basestring json.encoder.encode_basestring_ascii = _default_encode_basestring_ascii return result 一个免费的示例运行: >>> my_data = { ... 'something1': 5.5,... 'something2': u'Some info',... 'something3': b'x01x03x00x00 ...x00x00',... } >>> import json >>> r = json.dumps(my_data,cls=MyJsonEncoder) >>> print r {"something2": "Some info","something3": "AQMAACDm...AAAA==n","something1": 5.5} >>> r = json.dumps(my_data) Traceback (most recent call last): File "<stdin>",in <module> File "/usr/lib/python2.7/json/__init__.py",in dumps return _default_encoder.encode(obj) File "/usr/lib/python2.7/json/encoder.py",_one_shot=True) File "/usr/lib/python2.7/json/encoder.py",0) UnicodeDecodeError: 'utf8' codec can't decode byte 0xe6 in position 5: invalid continuation byte 嵌套测试. >>> json.dumps({'some': {'nested': {'data': [b'xe0x01x02x03?']}}},cls=MyJsonEncoder) '{"some": {"nested": {"data": ["4AECAz8=n"]}}}' (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |