Обробляти помилку декодування JSON, коли нічого не поверталося


80

Я аналізую дані 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)

Який найкращий спосіб усунути цю помилку?


3
Насправді, яке ваше запитання?
Tadeck

Ви відповіли на запитання;) Схоже, я подаю питання перед тим, як насправді ввести питання. Дякую за відповідь.
доповнення крапками з комою

2
Добре, я радий, що допоміг - це зараз схоже на телепатію;) Дякую за те, що включили питання. Удачі!
Tadeck

Відповіді:


153

У програмуванні на 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'

EDIT : Оскільки simplejson.decoder.JSONDecodeErrorнасправді успадковується від ValueError( доказ тут ), я спростив оператор catch, просто використовуючи ValueError.


11
Завжди слід ловити правильний виняток. В іншому випадку ви можете пропустити помилку в коді, якщо існує фактичний ValueErrorвиняток або інший виняток, який також успадковується від ValueError.
Джулі в Остіні

2
@JulieinAustin: проблема в тому, що в цьому випадку у вас дійсно немає великого вибору - модуль json stdlib викидає ValueError.
Тадек

2
Тоді я триматимуся подалі від цього декодера. Початкове запитання стосувалось simplejsonмодуля, і він дуже піднімає JSONDecodeErrorпоганий вхід. Перегляньте своє попереднє посилання.
Джулі в Остіні

3
@JulieinAustin: Я б вчинив інакше, оскільки це насправді ... стандартна бібліотека. Якщо вас занадто не турбує швидкість , я б використав те, що вже доступно. Так, simplejsonробить це більш детально, але у нього є свої проблеми. Що б ви сказали, якби try...exceptблок лише інкапсулював json.loadsвиклик? Тоді я думаю, що це було б краще, але для цього потрібне якесь котельне місце, щоб відповідати вимогам (наприклад, змінити клас винятку на щось більш дрібнозернисте, але не будемо намагатися врятувати світ тут).
Тадек

3
ValueErrorзанадто широкий для використання в цьому контексті. З точки зору користувацького коду qUserData["all"]["questions"]може кинути ValueErrorтеж я вважаю. Не кажучи вже про ValueErrorістоту, яку вирощують десь усередині simplejson. Це те, що могло б вас покусати по-справжньому 6 місяців, коли речі починають руйнуватися «без причини»
Ентоні Меннінг-Франклін,

10

Якщо ви не проти імпортувати 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 Лі в коментарі, не може бути основним загальним 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

На жаль, json.loads видає TypeError, коли об'єкт JSON не є str, bytes або bytearray. Нещодавно це мене покусало, бо я думав, що JSONDecodeError обробляє ці обставини, наприклад, коли аргумент json.loads закінчується None.
Jacob Lee

1
@JacobLee: Дякую. Початкове питання стосується найкращого способу вирішення цієї проблеми, JSONDecodeErrorтому я зосередився лише на цьому, але ви маєте рацію, і цей випадок, безумовно, варто згадати. Я додав це у відповідь.
pesekon2
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.