python – 如何覆盖JSONEncoder的二进制数据行为?

python – 如何覆盖JSONEncoder的二进制数据行为?,第1张

概述我在 Python 2.7.10中工作,我有一些二进制数据: binary_data = b'\x01\x03\x00\x00 \xe6\x10\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 我在 Python 2.7.10中工作,我有一些二进制数据:

binary_data = b'\x01\x03\x00\x00 \xe6\x10\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

(如果你真的很好奇,那就是几何的Extended WKB.)

实际上,我在dict中的某个地方有这些数据:

my_data = {    'something1': 5.5,'something2': u'Some info','something3': b'\x01\x03\x00\x00 \xe6\x10\x00\x00\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',}

我想将其序列化为JsON来存储它.问题是我收到错误,因为Json错误地尝试将其解释为UTF-8:

>>> Json.dumps(my_data)Traceback (most recent call last):  file "<input>",line 1,in <module>  file "C:\Python\lib\Json\__init__.py",line 243,in dumps    return _default_encoder.encode(obj)  file "C:\Python\lib\Json\encoder.py",line 207,in encode    chunks = self.iterencode(o,_one_shot=True)  file "C:\Python\lib\Json\encoder.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:\Python\lib\Json\encoder.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 Jsonimport Json.encoderimport binascii_default_encode_basestring = Json.encoder.encode_basestring_default_encode_basestring_ascii = Json.encoder.encode_basestring_asciidef _check_string(s):    if isinstance(s,str):        try:            s.decode('utf8')        except UnicodeDecodeError:            return False    return Truedef _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'\x01\x03\x00\x00 ...\x00\x00',... }>>> 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'\xe0\x01\x02\x03?']}}},cls=MyJsonEncoder)'{"some": {"nested": {"data": ["4AECAz8=\n"]}}}'
总结

以上是内存溢出为你收集整理的python – 如何覆盖JSONEncoder的二进制数据行为?全部内容,希望文章能够帮你解决python – 如何覆盖JSONEncoder的二进制数据行为?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1197354.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-03
下一篇 2022-06-03

发表评论

登录后才能评论

评论列表(0条)

保存