Обработка ошибок json python

The above Idea is good but I had problem with that. My json Sting consisted only one additional double quote in it.
So, I made a fix to the above given code.

The jsonStr was

{
    "api_version": "1.3",
    "response_code": "200",
    "id": "3237490513229753",
    "lon": "38.969916127827",
    "lat": "45.069889625267",
    "page_url": null,
    "name": "ATB",
    "firm_group": {
        "id": "3237499103085728",
        "count": "1"
    },
    "city_name": "Krasnodar",
    "city_id": "3237585002430511",
    "address": "Turgeneva,   172/1",
    "create_time": "2008-07-22 10:02:04 07",
    "modification_time": "2013-08-09 20:04:36 07",
    "see_also": [
        {
            "id": "3237491513434577",
            "lon": 38.973110606808,
            "lat": 45.029031222211,
            "name": "Advance",
            "hash": "5698hn745A8IJ1H86177uvgn94521J3464he26763737242Cf6e654G62J0I7878e",
            "ads": {
                "sponsored_article": {
                    "title": "Center "ADVANCE",
                    "text": "Business.English."
                },
                "warning": null
            }
        }
    ]
}

The fix is as follows:

import json, re
def fixJSON(jsonStr):
    # Substitue all the backslash from JSON string.
    jsonStr = re.sub(r'\', '', jsonStr)
    try:
        return json.loads(jsonStr)
    except ValueError:
        while True:
            # Search json string specifically for '"'
            b = re.search(r'[w|"]s?(")s?[w|"]', jsonStr)

            # If we don't find any the we come out of loop
            if not b:
                break

            # Get the location of "
            s, e = b.span(1)
            c = jsonStr[s:e]

            # Replace " with '
            c = c.replace('"',"'")
            jsonStr = jsonStr[:s] + c + jsonStr[e:]
        return json.loads(jsonStr)

This code also works for JSON string mentioned in problem statement


OR you can also do this:

def fixJSON(jsonStr):
    # First remove the " from where it is supposed to be.
    jsonStr = re.sub(r'\', '', jsonStr)
    jsonStr = re.sub(r'{"', '{`', jsonStr)
    jsonStr = re.sub(r'"}', '`}', jsonStr)
    jsonStr = re.sub(r'":"', '`:`', jsonStr)
    jsonStr = re.sub(r'":', '`:', jsonStr)
    jsonStr = re.sub(r'","', '`,`', jsonStr)
    jsonStr = re.sub(r'",', '`,', jsonStr)
    jsonStr = re.sub(r',"', ',`', jsonStr)
    jsonStr = re.sub(r'["', '[`', jsonStr)
    jsonStr = re.sub(r'"]', '`]', jsonStr)

    # Remove all the unwanted " and replace with ' '
    jsonStr = re.sub(r'"',' ', jsonStr)

    # Put back all the " where it supposed to be.
    jsonStr = re.sub(r'`','"', jsonStr)

    return json.loads(jsonStr)

Я разбираю данные json. У меня нет проблем с синтаксическим анализом, и я использую модуль simplejson. Но некоторые запросы api возвращают пустое значение. Вот мой пример:

{
"all" : {
    "count" : 0,
    "questions" : [     ]
    }
}

Это сегмент моего кода, в котором я разбираю объект json:

 qByUser = byUsrUrlObj.read()
 qUserData = json.loads(qByUser).decode('utf-8')
 questionSubjs = qUserData["all"]["questions"]

Как я уже упоминал, для некоторых запросов я получаю следующую ошибку:

Traceback (most recent call last):
  File "YahooQueryData.py", line 164, in <module>
    qUserData = json.loads(qByUser)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/__init__.py", line 385, in loads
    return _default_decoder.decode(s)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/decoder.py", line 402, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/simplejson/decoder.py", line 420, in raw_decode
    raise JSONDecodeError("No JSON object could be decoded", s, idx)
simplejson.decoder.JSONDecodeError: No JSON object could be decoded: line 1 column 0 (char 0)

Как лучше всего справиться с этой ошибкой?

2 ответа

Лучший ответ

В программировании на Python есть правило, которое называется «Проще просить прощения, чем разрешения» (вкратце: EAFP). Это означает, что вы должны перехватывать исключения, а не проверять значения на достоверность.

Таким образом, попробуйте следующее:

try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except ValueError:  # includes simplejson.decoder.JSONDecodeError
    print('Decoding JSON has failed')

ИЗМЕНИТЬ : поскольку simplejson.decoder.JSONDecodeError фактически наследуется от ValueError (здесь), я упростил оператор catch, просто используя ValueError.


193

aheze
10 Дек 2021 в 04:08

Если вы не против импорта модуля json, то лучший способ справиться с этим — использовать json.JSONDecodeError (или json.decoder.JSONDecodeError, поскольку они такие же), как и использовать ошибки по умолчанию, такие как ValueError может также перехватить другие исключения, не обязательно связанные с json-декодирующим.

from json.decoder import JSONDecodeError


try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
    # do whatever you want

// РЕДАКТИРОВАТЬ (октябрь 2020 г.):

Как отметил в комментарии @Jacob Lee, может возникнуть основная распространенная ошибка TypeError, когда объект JSON не является str, bytes или bytearray. Ваш вопрос касается JSONDecodeError, но все же стоит упомянуть здесь в качестве примечания; Чтобы справиться также с этой ситуацией, но различать разные проблемы, можно использовать следующее:

from json.decoder import JSONDecodeError


try:
    qByUser = byUsrUrlObj.read()
    qUserData = json.loads(qByUser).decode('utf-8')
    questionSubjs = qUserData["all"]["questions"]
except JSONDecodeError as e:
    # do whatever you want
except TypeError as e:
    # do whatever you want in this case


22

pesekon2
31 Окт 2020 в 15:55

JSON (JavaScript Object Notation-формат передачи данных), определен стандартом RFC 7159 (который вытекает из устаревшей версии RFC 4627) и ECMA-404, легким текстовым форматом обмена данных, основанным на синтаксисе литералов объекта JavaScript (хотя он и не является подгруппой JavaScript).

json предоставляет API, знакомый пользователям стандартных библиотечных модулей marshal и pickle.

Преобразование базовых объектов в Python в json:

>>> import json
>>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
'["foo", {"bar": ["baz", null, 1.0, 2]}]'
>>> print(json.dumps(""foobar"))
""foobar"
>>> print(json.dumps('u1234'))
"u1234"
>>> print(json.dumps('\'))
"\"
>>> print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
{"a": 0, "b": 0, "c": 0}
>>> from io import StringIO
>>> io = StringIO()
>>> json.dump(['streaming API'], io)
>>> io.getvalue()
'["streaming API"]'

Компактное преобразование:

>>> import json
>>> json.dumps([1, 2, 3, {'4': 5, '6': 7}], separators=(',', ':'))
'[1,2,3,{"4":5,"6":7}]'

Красивый вывод:

>>> import json
>>> print(json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4))
{
    "4": 5,
    "6": 7
}

Декодирование JSON, преобразование json в объект Python:

>>> import json
>>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
['foo', {'bar': ['baz', None, 1.0, 2]}]
>>> json.loads('"\"foo\bar"')
'"foox08ar'
>>> from io import StringIO
>>> io = StringIO('["streaming API"]')
>>> json.load(io)
['streaming API']

Специализированное декодирование объектов в JSON:

>>> import json
>>> def as_complex(dct):
...     if '__complex__' in dct:
...         return complex(dct['real'], dct['imag'])
...     return dct
...
>>> json.loads('{"__complex__": true, "real": 1, "imag": 2}',
...     object_hook=as_complex)
(1+2j)
>>> import decimal
>>> json.loads('1.1', parse_float=decimal.Decimal)
Decimal('1.1')

Расширение JSONEncoder:

>>> import json
>>> class ComplexEncoder(json.JSONEncoder):
...     def default(self, obj):
...         if isinstance(obj, complex):
...             return [obj.real, obj.imag]
...         # Let the base class default method raise the TypeError
...         return json.JSONEncoder.default(self, obj)
...
>>> json.dumps(2 + 1j, cls=ComplexEncoder)
'[2.0, 1.0]'
>>> ComplexEncoder().encode(2 + 1j)
'[2.0, 1.0]'
>>> list(ComplexEncoder().iterencode(2 + 1j))
['[2.0', ', 1.0', ']']

Рекомендуется использование json.tool для проверки и красивого вывода:

$ echo '{"json":"obj"}' | python -m json.tool
{
    "json": "obj"
}
$ echo '{1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

JSON является подмножеством YAML 1.2 JSON создан с помощью стандартных настроек этого модуля и также является подмножеством YAML 1.0 and 1.1. Этот модуль может использоваться в качестве сериализатора YAML.

До Python 3.7 порядок ключей словаря не сохранялся, поэтому входные и выходные данные, как правило, отличались. Начиная с Python 3.7, порядок ключей стал сохраняться, поэтому больше нет необходимости использовать collections.OrderedDict для парсинга JSON.

Основные методы

Метод json dump

json.dump(obj, fp, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

Сериализует obj в JSON-подобный формат записывая его в fp (который поддерживает .write()) используя эту таблицу.

Если skipkeys=True (по умолчанию: False), тогда ключи словаря не базового типа (str, int, float, bool, None) будут пропущены, вместо того, чтобы вызывать исключение TypeError.

Модуль json всегда создает объекты str, не bytes. Следовательно, fp.write() должен поддерживать ввод str.

Когда ensure_ascii=True (по умолчанию), все не-ASCII символы в выводе будут экранированы последовательностями uXXXX,. Если ensure_ascii=False, эти символы будут записаны как есть.

Когда check_circular=False (по умолчанию: True), тогда проверка циклических ссылок для типов контейнера будет пропущена, а такие ссылки будут вызывать OverflowError (или ошибку серьёзнее).

Если allow_nan=False (по умолчанию: True), при каждой попытке сериализировать значение float, выходящее за допустимые пределы (nan, inf, -inf), будет возникать ValueError, в соответствии с сертификацией JSON. В случае если allow_nan=True, будут использованы JavaScript аналоги (NaN, Infinity, -Infinity).

Когда indent является неотрицательным целым числом или строкой, то объекты и массивы JSON будут выводиться с этим количеством отступов. Если уровень отступа равен 0, отрицательный или "", будут использоваться новые строки без отступов. None (по умолчанию) отражает наиболее компактное представление. Если indent строка (например, "t"), эта строка используется в качестве отступа.

Изменения в версии 3.2: Допускаются строки для отступа в дополнение к целым числам.

Separators должны быть tuple (item_separator, key_separator). По умолчанию используется значение (', ', ': ') если indent=None и (',', ': ') при другом значении. Чтобы получить наиболее компактное представление JSON, вы должны указать (',', ':').

Изменения в версии 3.4: Используйте(',', ': ') при отступе None.

Значение default должно быть функцией. Он вызывается для объектов, которые не могут быть сериализованы. Функция должна вернуть кодируемую версию объекта JSON или вызывать TypeError. Если default не указано, возникает ошибка TypeError.

Если sort_keys=True (по умолчанию: False), ключи выводимого словаря будут отсортированы.

Чтобы использовать собственный подкласс JSONEncoder (например, тот который переопределяет метод default() для сериализации дополнительных типов), укажите его с помощью аргумента cls; в противном случае используется JSONEncoder.

Метод json dumps

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

Сериализирует obj в строку str формата JSON с помощью таблицы конвертации. Аргументы имеют то же значение, что и для dump().

Ключи в парах ключ/значение всегда являются строками. Когда словарь конвертируется в JSON, все ключи словаря преобразовываются в строки. Если в результате, сначала конвертировать его в JSON, а потом обратно, новый в словарь может отличаться от, то можно получить словарь идентичный исходному. Другими словами, loads(dumps(x)) != x если x имеет не строковые ключи.

Метод json load

json.load(fp, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

Десериализует из fp (текстовый или бинарный файл, который поддерживает метод .read() и содержит JSON документ) в объект Python используя эту таблицу конвертации.

object_hook — опциональная функция, которая применяется к результату декодирования объекта. Использоваться будет значение, возвращаемое этой функцией, а не полученный словарь dict. Эта функция используется для реализации пользовательских декодеров (например JSON-RPC).

object_pair_shook — опциональная функция, которая применяется к результату декодирования объекта с определенной последовательностью пар ключ/значение. Вместо исходного словаря dict будет использоваться результат, возвращаемый функцией. Эта функция используется для реализации пользовательских декодеров. Если задан object_hook, object_pairs_hook будет в приоритете.

В случае определения parse_float, он будет вызван для каждого значения JSON с плавающей точкой. По умолчанию, это эквивалентно float(num_str). Можно использовать другой тип данных или парсер для этого значения (например decimal.Decimal)

В случае определения parse_int, он будет вызван для декодирования строк JSON int. По умолчанию, эквивалентен int(num_str). Можно использовать другой тип данных или парсер для этого значения (например float).

В случае определения parse_constant, он будет вызван для строк: -Infinity, Infinit, NaN. Может быть использован для вызова исключений при обнаружении недопустимых чисел JSON. parse_constant больше не вызывается при null, true, fasle.

Чтобы использовать собственный подкласс JSONDecoder, укажите его с помощью аргумента cls; в противном случае используется JSONDecoder. Дополнительные аргументы ключевого слова будут переданы конструктору класса.

Если десериализованные данные не являются допустимым документом JSON, возникнет JSONDecodeError.

Метод json loads

json.loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

Десериализует s (экземпляр str, bytes или bytearray, содержащий JSON документ) в объект Python используя таблицу конвертации.

Остальные аргументы аналогичны аргументам в load(), кроме кодировки, которая устарела либо игнорируется.

Если десериализованные данные не являются допустимым документом JSON, возникнет ошибка JSONDecodeError.

Кодировщики и декодировщики

JSONDecoder

Класс json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None)

Простой декодер JSON. При декодировании выполняет следующие преобразования:

JSON Python
object dict
array list
string str
number (int) int
number (real) float
true True
false False
null None

Он также понимает NaN, Infinity, и -Infinity как соответствующие значения float, которые находятся за пределами спецификации JSON.

object_hook будет вызван для каждого значения декодированного объекта JSON, а его возвращаемое значение будет использовано в указанном месте dict. Может быть использовано для обеспечения десериализации (например, для поддержки JSON-RPC class hinting).

object_pairs_hook будет вызван для каждого значения декодированного объекта JSON с упорядоченным списком пар. Возвращаемое значение object_pairs_hook будет использовано вместо dict. Эта функция может использоваться для запуска стандартного декодера. Если object_hook так же определён, в приоритете будет object_pairs_hook.

parse_float будет вызван для каждого значения JSON с плавающей точкой. По умолчанию, это эквивалентно float(num_str). Может быть использован для другого типа данных или парсера JSON float. (например, decimal.Decimal).

parse_int будет вызван для строки JSON int. По умолчанию, эквивалентно int(num_str). Может быть использован для других типов данных и парсеров целых чисел JSON (например, float).

parse_constant будет вызван для строк: '-Infinity', 'Infinity', 'NaN'. Можно  использовать для вызова исключений при обнаружении недопустимых чисел JSON.

Если strict=False (True по умолчанию), тогда использование управляющих символов внутри строк будет разрешено. В данном контексте управляющие символы — это символы с кодами в диапазоне 0–31, включая t (tab), n, r и .

Если десериализованные данные не являются допустимым документом JSON, будет вызвана ошибка JSONDecodeError.

decode(s)
Возвращает представление s в Python (str — содержащий документ JSON). JSONDecodeError будет вызвана, если документ JSON не валидный (или не действительный).

raw_decode(s)
Декодирует документ JSON из s (str начинающийся с JSON документа) и возвращает кортеж из 2-х элементов (представление Python и индекс строки в s, на которой закончился документ). Может использоваться для декодирования документа JSON из строки, которая имеет дополнительные данные в конце.

JSONEncoder

Класс json.JSONEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)

Расширяемый кодировщик JSON для структур данных Python.
Поддерживает следующие типы данных и объекты по умолчанию:

Python JSON
dict object
list, tuple array
str string
int, float number
True true
False false
None null

Для того, чтобы можно было распознавать и другие объекты, подкласс должен выполнить метод default(), который вернет сериализуемый объект для o, если это возможно, в противном случае он должен вызвать реализацию родительского класса (для вызова TypeError).

Если skipkeys=False (по умолчанию), вызывается TypeError при попытке кодировать ключи, которые не являются str, int, float или None. В случае если skipkeys=True, такие элементы просто пропускаются.

Если ensure_ascii=True (по умолчанию), на выходе гарантируется, что все входящие не ASCII символы экранируются последовательностями uXXXX. Но если ensure_ascii=False, эти символы будут выводиться как есть.

Если check_circular=True (по умолчанию), тогда списки, словари и самостоятельно закодированные объекты будут проверяться на циклические ссылки во время кодировки, чтобы предотвратить бесконечную рекурсию (что вызовет OverflowError). В другом случае, такая проверка не выполняется.

Если allow_nan=True (по умолчанию), тогда NaN, Infinity, и -Infinity будут кодированы как таковые. Это не соответствует спецификации JSON, но соответствует большинству кодировщиков и декодеров на основе JavaScript. В другом случае такие значения вызовут ValueError.

Если sort_keys=True (по умолчанию: False), выводимый словарь будет отсортирован по именам ключей; это полезно для регрессивного тестирования, чтобы сравнивать сериализацию JSON ежедневно.

Если indent является неотрицательным целым числом или строкой, то объекты и массивы JSON будут выводиться с этим количеством отступов. Если уровень отступа равен 0, отрицательный или "", будут использоваться новые строки без отступов. None (по умолчанию) отражает наиболее компактное представление. Если indent строка (например, "t"), эта строка используется в качестве отступа.

Если указан separator (должен быть tuple типа (item_separator, key_separator)). По умолчанию используется (', ', ': ') если indent=None и (',', ': ') если нет. Для получения наиболее компактного представления JSON , вам следует использовать (',', ':'), чтобы уменьшить количество пробелов.

Значение default должно быть функцией. Она вызывается для объектов, которые не могут быть сериализованы. Функция должна вернуть кодируемую версию объекта JSON или вызывать TypeError. Если default не указано, возникает ошибка TypeError.

default(o)
Внедрите этот метод в подкласс таким образом, чтобы он возвращал сериализуемый объект для o или вызывал базовую реализацию (для повышения TypeError).

Например, чтобы поддерживать произвольные итераторы, вы можете реализовать default следующим образом:

def default(self, o):
   try:
       iterable = iter(o)
   except TypeError:
       pass
   else:
       return list(iterable)
   # Пусть базовый класс вызовет исключение TypeError
   return json.JSONEncoder.default(self, o)

encode(o)
Возвращает строковое представление JSON структуры данных Python. Пример:

>>> json.JSONEncoder().encode({"foo": ["bar", "baz"]})
'{"foo": ["bar", "baz"]}'

iterencode(o)
Кодирует переданный объект o и выдаёт каждое строковое представление, как только оно становится доступным. Например:

for chunk in json.JSONEncoder().iterencode(bigobject):
    mysocket.write(chunk)

Исключение JSONDecodeError

Исключение json.JSONDecodeError(msg, doc, pos)
Подкласс ValueError с дополнительными атрибутами:

msg — не отформатированное сообщение об ошибке.
doc — парсинг JSON документа.
pos — первый индекс doc, если парсинг неудачный.
lineno — строка, соответствующая pos.
colno — колонка, соответствующая pos.

Стандартное соответствие и совместимость

Формат JSON указан в RFC 7159 и ECMA-404. В этом разделе описывается уровень соответствия этого модуля с RFC. Для упрощения, подклассы JSONEncoder и JSONDecoder, и параметры, которые отличаются от указанных, не берутся во внимание.

Этот модуль не соответствует RFC, устанавливая некоторые расширения, которые являются рабочими для JavaScript, но недействительными для JSON. В частности:

  • Infinite и NaN принимаются и выводятся;
  • Повторяемые имена внутри объекта принимаются и выводятся, но только последнее значение дублируемого ключа.

Поскольку RFC разрешает синтаксическим анализаторам, совместимым с RFC, принимать входные тексты, которые не соответствуют требованиям RFC, десериализатор этого модуля технически соответствует стандартным настройкам RFC.

Декодировка символов

RFC требует, чтобы JSON был представлен с использованием UTF-8, UTF-16 или UTF-32, при том, что UTF-8 является рекомендуемым по умолчанию для максимальной совместимости.

Возможно, но не обязательно для RFC, сериализаторы этого модуля устанавливают ensure_ascii=True по умолчанию, таким образом строки содержат только символы ASCII.

Кроме параметра ensure_ascii, этот модуль напрямую не затрагивает проблему кодировки символов.

RFC запрещает маркер последовательности байтов (BOM) в начало текста JSON и сериализатор этого модуля не добавляет BOM. RFC позволет, не не требует десериализаторы JSON игнорировать BOM на входе. Десериализатор этого модуля вызывает ValueError при наличии BOM.

RFC явно не запрещает строки JSON, содержащие последовательность байт, которая не соответствует валидным символам Unicode (например, непарные UTF-16 заменители), он отмечает — они могут вызывать проблемы совместимости. По умолчанию этот модуль принимает и выводит (если есть в исходной строке) специальные последовательности кода.

Infinite и NaN

RFC не допускает представления для значений infinite или NaN. Несмотря на это, по умолчанию этот модуль принимает и выводит Infinity, -Infinity, и NaN, как если бы они были действительно буквальными значениями числа в JSON:

>>> # Ни один из этих вызовов не будет исключением, но результаты не являются JSON
>>> json.dumps(float('-inf'))
'-Infinity'
>>> json.dumps(float('nan'))
'NaN'
>>> # То же самое при дезериализации
>>> json.loads('-Infinity')
-inf
>>> json.loads('NaN')
nan

В сериализаторе параметр allow_nan используется для изменения этого поведения. В десериализаторе параметр этот переметр — parse_constant.

Повторяющиеся имена внутри объекта

RFC указывает, что имена в объекте JSON должны быть уникальными, но не указывает, как должны обрабатываться повторяющиеся имена в объектах JSON. По умолчанию этот модуль не вызывает исключения; вместо этого он игнорирует все, кроме последней пары ключ/значение для данного ключа:

>>> weird_json = '{"x": 1, "x": 2, "x": 3}'
>>> json.loads(weird_json)
{'x': 3}

Параметр object_pairs_hook может использоваться для изменения этого.

Значение верхнего уровня Non-Object, Non-Array

Старая версия JSON указанная устаревшим RFC 4627 требовала, чтобы значение верхнего уровня текста JSON было объектом JSON или массивом (Python dict или list), или не было JSON null, boolean, number, string value. RFC 7159 убрало это ограничение, поэтому этот модуль не выполнял и никогда не применял это ограничение ни в своем сериализаторе, ни в десериализаторе.

Тем не менее, для максимальной совместимости, вы можете добровольно придерживаться этого ограничения.

Ограничения реализации

Некоторые реализации десериализатора JSON имеют лимиты на:

  • размер принимаемого текста JSON
  • максимальный уровень вложенности объектов и массивов JSON
  • диапазон и точность чисел JSON
  • содержание и максимальная длина строк JSON

Этот модуль не ставит никаких ограничений, кроме тех, которые относятся к соответствующим типам Python или самому интерпретатору Python.

При сериализации в JSON будьте осторожны с такими ограничениями в приложениях, которые могут потреблять ваш JSON. В частности, числа в JSON часто десериализуются в числа двойной точности IEEE 754 и подвержены ограничениям диапазона и точности этого представления. Это особенно актуально при сериализации значений Python int чрезвычайно большой величины или при сериализации экземпляров «необычных» числовых типов, таких как decimal.Decimal.

Интерфейс командной строки

Исходный код: Lib/json/tool.py

Модуль json.tool обеспечивает простой интерфейс командной строки для проверки и вывода объектов JSON.

Если не обязательные аргументы infile и outfile не указаны, sys.stdin и sys.stdout будут соответственно:

$ echo '{"json": "obj"}' | python -m json.tool
{
 "json": "obj"
$ echo '{"json": "obj"}' | python -m json.tool
{
    "json": "obj"
}
$ echo '{1.2:3.4}' | python -m json.tool
Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

Возможности командной строки

infile
Проверки и красивого вывод файла JSON:

$ python -m json.tool mp_films.json
[
	{
		"title": "And Now for Something Completely Different",
		"year": 1971
	},
	{
		"title": "Monty Python and the Holy Grail",
		"year": 1975
	}
]
$ python -m json.tool mp_films.json
[
    {
        "title": "And Now for Something Completely Different",
        "year": 1971
    },
    {
        "title": "Monty Python and the Holy Grail",
        "year": 1975
    }
]$ python -m json.tool mp_films.json
[
	{
		"title": "And Now for Something Completely Different",
		"year": 1971
	},
	{
		"title": "Monty Python and the Holy Grail",
		"year": 1975
	}
]

Если infile не указан, чтение из sys.stdin.

outfile
Запишет вывод из infile в данный outfile. В противном случае, запишет его в sys.stdout.

--sort-keys
Сортировка выводимых словарей в алфавитном порядке по ключам.

-h, --help
Показать справку.

Что из перечисленного ниже НЕ верно для формата JSON файла?

Json простой и легко читаемый формат

JSON состоит из пар ключ-значение

Функция json.load() загрузит JSON на Python в виде списка

Функция json.load() загрузит JSON на Python в виде словаря

Как преобразовать словарь data = {"key1" : "value1", "key2" : "value2"} в Json объект?

Как вывести читаемый json c отступами

Модуль JSON Python для работы с форматом .json

json.dumps(data, separators=»,n «)

json.dumps(data, indent=2)

json.dumps(data, indent=(2,2,2))

json.dumps(data, pretty_print=True)

Как проверить json на валидность с помощью командной строки?

python json.py —validate ‘{«Name»: «Bah»}’

echo ‘{«Name»: «Bah»}’ python -m json.tool

echo ‘{«Name»: «Bah»}’ | python -m json.tool

echo {«Name»: «Bah»} | python -m json.tool

Какая структура данных Json НЕ соответствует типу данных Python?

В мире программирования данные часто хранятся и передаются в различных форматах в другие части приложения или других веб-служб. Чтобы упростить передачу данных между сервисами, написанными на разных языках и фреймворках (такими как серверная часть Java, взаимодействующая со службой Python и отправляющая результаты во внешний интерфейс JavaScript), были опробованы, протестированы и приняты общие форматы.

Одним из наиболее часто используемых форматов обмена данными является JSON (JavaScript Object Notation).

Он удобочитаем, интуитивно понятен, эффективен и быстр, и быстро стал стандартом де-факто для форматов обмена данными с появлением JavaScript в Интернете.

Преобразование между объектами JSON и Python полезно, поскольку оно позволяет приложениям Python работать с данными из внешних источников или веб-API, использующих формат JSON. JSON — это упрощенный формат обмена данными, ставший стандартом для многих веб-API, что делает его популярным выбором для обмена данными между веб-приложениями.

Python — это мощный язык программирования, предоставляющий богатый набор структур данных и инструментов манипулирования, которые можно использовать для обработки и анализа данных JSON различными способами. Например, встроенные в Python словари и списки можно использовать для хранения объектов и массивов JSON естественным образом и управления ими, в то время как модуль json предоставляет методы для сериализации и десериализации данных JSON в объекты Python и из них.

И наоборот, преобразование объектов Python в JSON полезно, когда необходимо передавать данные между различными системами или приложениями, которые могут быть написаны не на Python. JSON — это широко поддерживаемый формат, который может быть прочитан и записан многими языками программирования, что делает его гибким выбором для обмена данными.

В целом, способность конвертировать между объектами JSON и Python является важным навыком для любого разработчика Python, работающего с веб-API или внешними источниками данных. Это позволяет им работать с данными естественным и интуитивно понятным способом, сохраняя при этом совместимость с другими системами и языками.

В этой статье мы рассмотрим, как преобразовать JSON в объект Python.

Преобразование JSON в объекты Python

Python предоставляет встроенный модуль json, который позволяет легко конвертировать данные json в объекты Python. Функция json.loads() используется для загрузки данных JSON из строки и преобразования их в соответствующий объект Python:

import json

json_string = '{"name": "John Doe", "age": 30, "is_student": false}'

python_obj = json.loads(json_string)

print(python_obj)

В этом примере мы сначала импортируем модуль json. Затем мы определяем образец строки JSON и сохраняем ее в переменной json_str.

Чтобы преобразовать строку JSON в объект Python, мы используем функцию json.loads(), которая принимает строку JSON в качестве входных данных и возвращает соответствующий объект Python. Мы сохраняем результирующий объект Python в переменной python_obj.

Наконец, мы печатаем объект Python с помощью функции print(). Результат будет выглядеть следующим образом:


{'name': 'John Smith', 'age': 35, 'is_student': False}

Обратите внимание, что логическое значение JSON false преобразуется в логическое значение Python False. Точно так же null значение JSON преобразуется в None Python.

Понимание функции json.loads()

Функция json.loads() принимает строку JSON в качестве входных данных и возвращает соответствующий объект Python.

Это распространенное заблуждение, что имя метода — «loads», как в настоящем простом времени «load». Фактически, название метода является сокращением от «load string», что отражает тот факт, что оно предназначено для загрузки в формате строки, и указание имени файла не сработает. Метод load() работает с именами файлов.

Он также может использовать дополнительные параметры для настройки поведения процесса преобразования. Вот несколько важных моментов, на которые следует обратить внимание в отношении этой функции:

  • Это вызывает исключение ValueError, если входная строка недопустима в формате JSON.
  • Он может принимать второй параметр object_hook, который представляет собой функцию, которая может изменять декодированный объект. Эта функция вызывается для каждого декодированного объекта JSON и возвращает измененный объект. Функция object_hook может быть использована для анализа объекта JSON пользовательским способом.
  • Функция json.loads() также принимает несколько других необязательных параметров, о которых вы можете прочитать в документации Python.

Обработка ошибок

Важно обрабатывать ошибки при преобразовании JSON в объекты Python, чтобы предотвратить сбой вашей программы, если входные данные не являются допустимыми JSON. Метод json.loads() вызывает исключение ValueError, если входная строка не является допустимой JSON, поэтому вам следует обернуть вызов метода в блок try-except, чтобы перехватить это исключение и обработать его соответствующим образом.

Вот пример того, как обрабатывать ошибки при преобразовании JSON в объекты Python:

import json

# Define a JSON string with an error
json_str = '{"name": "John", "age": 30, "city": "New York"'

try:
    # Convert the JSON string to a Python object
    python_obj = json.loads(json_str)
    print(python_obj)
except ValueError as e:
    print("Error:", e)

В этом примере мы намеренно вносим ошибку в строку JSON, опуская закрывающую фигурную скобку в конце объекта. Когда мы пытаемся преобразовать строку в объект Python, метод json.loads() вызывает исключение ValueError. Мы перехватываем это исключение, используя блок try-except, и выводим сообщение об ошибке на консоль.

Преобразование объектов Python в JSON

В дополнение к преобразованию данных JSON в объекты Python, модуль json в Python также предоставляет способ преобразования объектов Python в данные JSON. Это может быть полезно при работе с веб-API, которые требуют отправки данных в формате JSON, или при хранении данных в файле JSON.

Чтобы преобразовать объект Python в данные JSON, мы можем использовать функцию json.dumps(), которая принимает объект Python в качестве входных данных и возвращает строку в формате JSON.

Примечание: Во многом таким же образом loads() является сокращением от «load string», dumps() является сокращением от «dump string».

Вот пример:

import json

# Define a Python dictionary
python_obj = {
    "name": "John",
    "age": 30,
    "city": "New York"
}

# Convert the Python object to a JSON-formatted string
json_str = json.dumps(python_obj)

# Print the JSON string
print(json_str)

В этом примере мы определяем словарь Python python_obj, который содержит те же данные, что и строка JSON, которую мы использовали в предыдущем примере. Затем мы используем функцию json.dumps() для преобразования объекта Python в строку в формате JSON, которую мы храним в переменной json_str. Наконец, мы выводим строку JSON на консоль.

Результатом этой программы должна быть строка JSON, которая выглядит следующим образом:

{"name": "John", "age": 30, "city": "New York"}

По умолчанию функция json.dumps() выдает компактную строку JSON без дополнительных пробелов. Однако мы можем управлять выходным форматом строки JSON, используя следующие параметры:

  • indent: Этот параметр определяет количество пробелов, используемых для отступа. Если значение отступа равно неотрицательному целому числу, выходные данные будут отформатированы с таким количеством пробелов для каждого уровня отступа. Если для indent установлено значение None (по умолчанию), выходные данные будут компактными, без дополнительных пробелов.
  • sort_keys: Этот параметр определяет, должны ли выходные ключи в строке JSON сортироваться в алфавитном порядке. Если для sort_keys установлено значение True, выходные ключи будут отсортированы. Если для sort_keys установлено значение False (по умолчанию), выходные ключи будут в том порядке, в котором они были вставлены.

Вот пример, в котором параметр indent используется для создания красиво напечатанной строки JSON:

import json

# Define a Python dictionary
python_obj = {
    "name": "John",
    "age": 30,
    "city": "New York"
}

# Convert the Python object to a pretty-printed JSON string
json_str = json.dumps(python_obj, indent=4)

# Print the JSON string
print(json_str)

В этом примере мы устанавливаем параметру indent значение 4, что приводит к тому, что выходные данные будут разделены четырьмя пробелами на каждый уровень отступа. Результатом этой программы должна быть красиво напечатанная строка JSON, которая выглядит следующим образом:

{
    "name": "John",
    "age": 30,
    "city": "New York"
}

Лучшие практики

При работе с данными JSON в Python важно следовать некоторым рекомендациям, чтобы убедиться, что данные правильно преобразованы и используются в программе. Вот несколько рекомендаций, которые следует учитывать при работе с данными JSON в Python.

Проверка данных JSON

Прежде чем пытаться преобразовать данные JSON в объекты Python, важно проверить данные, чтобы убедиться, что они правильно сформированы и не содержат никаких ошибок. Это можно сделать с помощью онлайн-инструментов или библиотек, специально разработанных для проверки JSON, таких как библиотека jsonschema в Python.

Обработка ошибок и исключений

При работе с данными JSON важно правильно обрабатывать ошибки и исключения. Это можно сделать, используя встроенные в Python механизмы обработки ошибок, такие как блоки try-except, для обработки ошибок, которые могут возникнуть в процессе преобразования.

Использование соответствующих типов данных

При преобразовании данных JSON в объекты Python важно использовать соответствующие типы данных, чтобы гарантировать точное представление данных в программе. Например, обеспечение того, чтобы числа JSON были представлены в виде объектов Python float или int, а строки JSON — в виде объектов Python string.

Понимание ограничений формата JSON

Хотя JSON является широко используемым форматом данных, у него есть некоторые ограничения. Например, он не поддерживает определенные типы данных, такие как дата-время или двоичные данные. В некоторых случаях вам может потребоваться сериализовать некоторые поля в определенном типе данных, а затем проанализировать их позже.

Вывод

В заключение отметим, что JSON — это широко используемый формат данных, который популярен для обмена данными между различными языками программирования и платформами. В Python встроенный модуль json предоставляет простой и эффективный способ преобразования данных JSON в объекты Python и наоборот.

Следуя рекомендациям, которые мы изложили в этой статье, таким как проверка данных JSON, обработка ошибок и исключений, использование соответствующих типов данных и понимание ограничений и вариантов использования данных JSON, разработчики могут эффективно работать с данными JSON в своих приложениях на Python. Работаете ли вы с веб-API, хранилищем данных или обменом данными, понимание того, как конвертировать JSON в объекты Python, является важным навыком для любого программиста на Python.

Время на прочтение
5 мин

Количество просмотров 6.4K

Продолжаем публикацию перевода серии статей о схожести и различии двух языков.

Сегодня поговорим о сериализации словарей, JSON, регулярках, об ошибках и исключениях.

Другие статьи в этой серии:

  1. Первая часть — приведение к типу, тернарный оператор, доступ к свойству по имени свойства, словари, списки, строки, конкатенация строк.
  2. Эта статья
  3. Часть третья: современные Python и JS: строковые шаблоны (f-строки), распаковка списков, лямбда-функции, итерации по спискам, генераторы, множества.
  4. Четвертая часть — аргументы функций, создание и работа с классами, наследование, геттеры-сеттеры и свойства класса.

JSON

При работе со многими API удобно сериализовать объекты в JSON-объекты для удобства передачи и последующего разбора.

В Питоне есть стандартный модуль json:

import json
json_data = json.dumps(dictionary, indent=4)
dictionary = json.loads(json_data)

Здесь мы форматируем JSON с помощью отступов в 4 пробела.

В JS существует объект JSON с методами для создания и парсинга JSON-строк:

json_data = JSON.stringify(dictionary, null, 4);
dictionary = JSON.parse(json_data);

Разбираем строки регулярками

В прошлой статье мы соединяли несколько строк в одну. Но как разделить одну длинную строку на несколько, особенно если разделителем выступает не один символ типа запятой, а целый диапазон различных вариантов? Здесь нам на помощь приходят регулярные выражения и метод split().

В Питоне метод split() относится к шаблону регулярных выражений. Вот как можно разделить текстовую строку на предложения по знакам препинания:

import re

# Один или более символов "!?." за которыми следует ноль или более пробельных символов
delimiter = re.compile(r'[!?.]+s*')

text = "Hello!!! What's new? Follow me."
sentences = delimiter.split(text)
# sentences == ['Hello', "What's new", 'Follow me', '']

В JS метод split() относится к строкам:

// Один или более символов "!?." за которыми следует ноль или более пробельных символов
delimiter = /[!?.]+s*/;

text = "Hello!!! What's new? Follow me.";
sentences = text.split(delimiter)
// sentences === ["Hello", "What's new", "Follow me", ""]

Поиск регулярками по шаблону

Регулярные выражения часто используются для валидации данных из форм.
К примеру, для проверки корректности веденного e-mail адреса его надо сопоставить с шаблоном регулярного выражения.

Автор перевода в курсе

что проверка адреса регулярками задача нетривиальная и несколько сложнее приведенного в этой статье метода

В Питоне это будет выглядеть примерно так:

import re

# name, "@", and domain
pattern = re.compile(r'([w.+-]+)@([w-]+.[w-.]+)')

match = pattern.match('hi@example.com')
# match.group(0) == 'hi@example.com'
# match.group(1) == 'hi'
# match.group(2) == 'example.com'

Если участок текста совпадает с шаблоном, то при помощи метода group() возвращается совпавший участок целиком в котором можно выделить отдельные группы определенные в шаблоне.

0 — совпавшая (под)строка целиком, 1 — первая группа, 2 — вторая и т.д.

Если совпадений не найдено, вернется объект типа None.

В JS существует строковый метод match()который возвращает либо совпавший участок строки либо null.

// name, "@", and domain
pattern = /([w.+-]+)@([w-]+.[w-.]+)/;

match = 'hi@example.com'.match(pattern);
// match[0] === 'hi@example.com'
// match[1] === 'hi'
// match[2] === 'example.com'

В JS совпавший объект выглядит как массив. Элемент с индексом [0] — совпавшая (под)строка целиком, 1-й элемент — первая группа, 2-й — вторая и т.д. — все в соответствии с группами определенными в шаблоне.

Иногда кроме поиска требуется определить положение образца в тексте. Это можно сделать с помощью метода search().
В Питоне этот метод относится к регулярным выражениям и возвращает совпавший объект. У этого совпавшего объекта есть метод start(), возвращающий начало вхождения этой подстроки в основную строку:

text = 'Say hi at hi@example.com'
first_match = pattern.search(text)
if first_match:
    start = first_match.start()  # start == 10

В JS метод есть строковый метод search() возвращающий индекс начала подстроки. Или -1 если совпадений не было найдено.


text = 'Say hi at hi@example.com';
first_match = text.search(pattern);
if (first_match > -1) {
    start = first_match;  // start === 10
}

Замена по шаблону с помощью регулярных выражений

Обычно замена по шаблону нужна когда требуется очистить данные или добавить какие-нибудь свойства в текст. К примеру, мы можем взять строку и все встречающиеся email-адреса сделать ссылками:

В Питоне для этого есть метод шаблона регулярных выражений sub():


html = pattern.sub(
    r'<a href="mailto:g<0>">g<0></a>',
    'Say hi at hi@example.com',
)
# html == 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

Разработчики на JS могут использовать строковый метод replace():

html = 'Say hi at hi@example.com'.replace(
    pattern, 
    '<a href="mailto:$&">$&</a>',
);
// html === 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

В Питоне совпавшие группы доступны как g<0>, g<1>, g<2> и т.д.
В JS аналогично $&, $1, $2 и т.д.

Также возможно заменить совпавший участок при помощи функции. Такие функции бывают полезны при замене оборачивании исходного текста или для подсчета, сбора или получения другой информации о тексте. К примеру, использую при замене вызов функции можно написать подсветку синтаксиса HTML.

Давайте изменим все встречающиеся e-mail адреса ПРОПИСНЫМИ БУКВАМИ.

В Питоне функция замены получает совпавший объект. Мы используем метод group() чтобы произвести действия с совпавшим текстом и вернуть его в виде замены:

text = pattern.sub(
    lambda match: match.group(0).upper(), 
    'Say hi at hi@example.com',
)
# text == 'Say hi at HI@EXAMPLE.COM'

В JS функция замены получает совпавшую строку целиком, первое вхождение, второе и т.д. Мы производим необходимые действия и возвращаем измененную строку:

text = 'Say hi at hi@example.com'.replace(
    pattern,
    function(match, p1, p2) {
        return match.toUpperCase();
    }
);
// text === 'Say hi at HI@EXAMPLE.COM'

Обработка ошибок

В противоположность Питону фронтенд-браузерный JavaScript обычно не используют для записи-чтения файлов или доступа к базам данных. Поэтому блоки try..catch довольно редко встречаются в JS по сравнению с блоками try..except в Питоне.

Но, в любом случае, обработка ошибок может быть произведена в пользовательском скрипте, вызвана из библиотечной функции и перехвачена в основном коде.

В следующем примере на Пионе мы определим свое исключение MyException, порождаем его в функции, и посмотрим как его перехватить и обработать в блоке try..except..finally:

class MyException(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message

def proceed():
    raise MyException('Error happened!')

try:
    proceed()
except MyException as err:
    print('Sorry! {}'.format(err))
finally:
    print('Finishing')    

Следующий код на JS делает то же самое — мы определяем класс MyException, порождаем его в функции, перехватываем и обрабатываем в блоке try..catch..finally:

function MyException(message) {
   this.message = message;
   this.toString = function() {
       return this.message;
   }
}

function proceed() {
    throw new MyException('Error happened!');
}

try {
    proceed();
} catch (err) {
    if (err instanceof MyException) {
        console.log('Sorry! ' + err);
    }
} finally {
    console.log('Finishing');
}

В обоих языках класс MyException имеет параметр message и метод для строкового представления в зависимости от значения message.

Конечно, исключения должны вызваться/порождаться только в случае ошибки. И если вы определили эту ошибку в своем модуле.

Выводы

  • Сериализация в/из JSON достаточно прямолинейна — что в Питоне что в JS.
  • Регулярки — мощный инструмент обработки текстов в обоих языках.
  • Можно производить замены с помощью функций.
  • Для более сложных случаев можно использовать вызов, перехват и обработку ошибок.

Как было сказано в прошлый раз, можно построчно сопоставить примеры кода приведенного здесь, чтобы понять схожие структуры данных и методы работы с ними: строки, массивы, словари, доступ к объектам.

В следующей части поговорим о текстовых шаблонах, распаковке списков, лямбда-функциях, итерациях без использования индексов, генераторах и множествах.

Понравилась статья? Поделить с друзьями:
  • Обработка ошибок java spring
  • Обработка ошибок swift
  • Обработка ошибок idhttp
  • Обработка ошибок socket
  • Обработка ошибок firebird delphi