jpm*_*c26 5 python json python-2.7
我正在使用 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'
Run Code Online (Sandbox Code Playgroud)
(如果您真的很好奇,那是几何体的扩展 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',
}
Run Code Online (Sandbox Code Playgroud)
我想将其序列化为 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
Run Code Online (Sandbox Code Playgroud)
我可以手动编码:
>>> 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
Run Code Online (Sandbox Code Playgroud)
给了一个很好的
'{"something2": "Some info", "something3": "AQMAACDmEAAAAQAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\\n", "something1": 5.5}'
Run Code Online (Sandbox Code Playgroud)
但这会很麻烦,因为我需要在整个应用程序中重做此操作。我更愿意自定义json这个二进制文件的行为。通常,您会json通过重写来告知如何序列化某些内容,JSONEncoder.default如下所示:
my_serializable_data = dict(my_data.items())
my_serializable_data['something3'] = binascii.b2a_base64(my_serializable_data['something3'])
json.dumps(my_serializable_data)
Run Code Online (Sandbox Code Playgroud)
但这没有效果,大概是因为 的处理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
Run Code Online (Sandbox Code Playgroud)
覆盖JSONEncoder.encode 应该可行,但我需要从内置库中重建大量逻辑,因为该方法知道如何深入挖掘lists 和dicts 的任意级别和组合。我宁愿不这样做;它会很快变得丑陋并且容易出错。(此外,查看源代码,看起来该逻辑可能位于中模块的全局json方法中,这使得这个想法更加混乱。)
这里的一个重要注意事项是,反序列化它以供以后使用对于这种情况不是问题。这是为了记录目的;当这些数据被反序列化时,它将供开发人员查看。如果他们确实需要对数据做一些事情,他们可以手动解码它。我也愿意做出权衡,如果某些文本作为 astr而不是 a出现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
Run Code Online (Sandbox Code Playgroud)
运行一个免费的示例:
>>> 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
Run Code Online (Sandbox Code Playgroud)
嵌套测试。
>>> json.dumps({'some': {'nested': {'data': [b'\xe0\x01\x02\x03?']}}}, cls=MyJsonEncoder)
'{"some": {"nested": {"data": ["4AECAz8=\\n"]}}}'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1780 次 |
| 最近记录: |