msgpack десериализация строк ключа dict в байты
У меня проблемы с msgpack
в питоне. Кажется, что при сериализации dict
, если ключи являются строками str
они не несериализованы должным образом и вызывают KeyError
исключения, которые будут подняты.
Пример:
>>> import msgpack
>>> d = dict()
>>> value = 1234
>>> d['key'] = value
>>> binary = msgpack.dumps(d)
>>> new_d = msgpack.loads(binary)
>>> new_d['key']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'key'
Это потому, что ключи не являются строками после вызова loads()
но не сериализованы bytes
объекты.
>>> d.keys()
dict_keys(['key'])
>>> new_d.keys()
dict_keys([b'key'])
Кажется, это связано с нереализованной функцией, упомянутой в github.
У меня вопрос: есть ли способ исправить эту проблему или обойти, чтобы гарантировать, что те же ключи могут быть использованы при десериализации?
Я хотел бы использовать msgpack
но если я не могу построить dict
объект с str
ключи и ожидают, что смогут использовать один и тот же ключ при десерилизации, он становится бесполезным.
2 ответа
Кодировка по умолчанию устанавливается при вызове dumps
или же packb
:param str encoding:
| Convert unicode to bytes with this encoding. (default: 'utf-8')
но это не установлено по умолчанию при вызове loads
или же unpackb
как видно в:
Help on built-in function unpackb in module msgpack._unpacker:
unpackb(...)
unpackb(... encoding=None, ... )
Поэтому изменение кодировки при десериализации устраняет проблему, например:
>>> d['key'] = 1234
>>> binary = msgpack.dumps(d)
>>> msgpack.loads(binary, encoding = "utf-8")
{'key': 1234}
>>> msgpack.loads(binary, encoding = "utf-8") == d
True
С использованием raw=False
флаг как таковой работал у меня на вашем примере:
msgpack.unpackb(binary, raw=False)
# or
msgpack.loads(binary, raw=False)
См. https://msgpack-python.readthedocs.io/en/latest/api.html:
raw (bool) - если true, распаковать msgpack raw в байты Python. В противном случае распакуйте в Python str путем декодирования с кодировкой UTF-8 (по умолчанию).
Попробуйте следующее:
def c_msgpackloads(bin):
new_d = msgpack.loads(bin)
new_d = {key.decode('utf-8') if isinstance(key, bytes) else key: new_d[key].decode('utf-8') if isinstance(new_d[key], bytes) else new_d[key] for key in new_d}
return new_d
Это пользовательская функция загрузки, которая загружает dict и автоматически кодирует bytes
ключи и значения для строк utf-8.