Python3 json.loads когато се подаде bytes

Публикувано на

Когато се мигрира от Python2 на Python3, може да се попадне в много неудобна ситуация, при която имате bytes обект, който искате да подадете на json.loads, и да ви го обърне в JSON. Тогава ще гръмне с TypeError, че очаква str а не bytes.

Някой би поспорил, че това е напълно коректно и трябва ние предварително да си декодираме bytes данните преди да ги подадем на json.loads. От Python 3.6 обаче може да се подаде bytes, който е кодиран като utf8, utf16 или utf32 и json.loads автоматично ще се оправи с това. При Python 2.7 ако данните са utf8, също няма да имате проблем с парсването.

Ако ползвате предимно utf8 (което трябва да ползвате) за пренос на данни, с един малък трик може да си направите кода съвместим с Python 2/3 без значение от версията и без да пипате нищо по него.

import json

try:
    json.loads(b'true')
except TypeError:
    # Python version is 2.7 < version < 3.6 and we can't pass bytes
    # to json.loads. For that reason we will monkeypatch it.
    _original_loads = json.loads

    def _loads(value, *args, **kwargs):
        if isinstance(value, bytes):
            try:
                value = value.decode('utf8')
            except UnicodeDecodeError:
                # If we can't decode it just pass it as is to original
                # function in order to see original exception.
                pass
        return _original_loads(value, *args, **kwargs)

    _loads.__name__ = _original_loads.__name__
    _loads.__doc__ = _original_loads.__doc__

    json.loads = _loads

Това може да го сложите в __init__.py на някой от пакетите ви и вече парсването на json, ще бъде много по-лесно.

blog comments powered by Disqus