gpt4 book ai didi

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

转载 作者:太空宇宙 更新时间:2023-11-03 11:49:19 27 4
gpt4 key购买 nike

我在 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\27\Lib\json\__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "C:\Python\27\Lib\json\encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:\Python\27\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 1, in <module>
File "C:\Python\27\Lib\json\__init__.py", line 250, in dumps
sort_keys=sort_keys, **kw).encode(obj)
File "C:\Python\27\Lib\json\encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "C:\Python\27\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

覆盖 JSONEncoder.encode 应该 工作,但我需要从内置库中重建大量逻辑,因为该方法知道如何深入挖掘任意listdict 的级别和组合。我不想那样做;它会很快变得丑陋并且容易出错。 (此外,查看源代码,看起来逻辑可能在 json 中的模块的 global 方法中,这使得这个想法更加困惑。)

这里需要注意的是,反序列化它以供以后使用在这种情况下不是问题。这是为了记录目的;当这些数据被反序列化时,它将供开发人员查看。如果他们真的需要对数据做些什么,他们可以手动解码就可以了。我也愿意做出权衡,如果某些文本以 str 而不是 unicode 的形式出现,它无论如何都会进行 base64 编码。 (或者,我可能会修改我的代码,如果它包含可打印 ASCII 之外的任何字符,我可能只对其进行 base64 编码,但在我能解决我在这里询问的问题之前,我什至无法做出那个决定。)

那么如何在不尝试重建太多 JSONEncoding 的情况下覆盖此行为?

最佳答案

你并不真的需要重建一切本身。一种廉价的出路是按照您的建议执行并覆盖 encode,但使用清理后的数据构建一个新的 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'\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>", line 1, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 243, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python2.7/json/encoder.py", line 207, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python2.7/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

嵌套测试。

>>> json.dumps({'some': {'nested': {'data': [b'\xe0\x01\x02\x03?']}}}, cls=MyJsonEncoder)
'{"some": {"nested": {"data": ["4AECAz8=\\n"]}}}'

关于python - 如何覆盖二进制数据的 JSONEncoder 行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31869554/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com