Подтвердить что ты не робот

Json.dump throwing "TypeError: {...} не является сериализуемым JSON" на, казалось бы, действительном объекте?

Фон. Я пишу программу python, которая должна управлять моими музыкальными файлами. Он сканирует каталоги и помещает файлы и их метаданные (через мутаген), закодированные в JSON, в файл как простую "базу данных". У меня есть поиск в обычном порядке, но когда я пытаюсь сохранить базу данных или закодировать ее в JSON, она выбрасывает "TypeError: {...} не является сериализуемым JSON" (... являются некоторыми ключами и значениями из dict, более подробно ниже)

Проблема: программа создает большой объект словаря, следующий за этим форматом:

{
    "<song id>":{
        "artist":"<song artist>",
        "album":"<song album>",
        "title":"<song title>"},
    ...
}

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

Traceback (most recent call last):
  File "<pyshell#2>", line 1, in <module>
    sit()
  File "D:\workbench\ideas\musicmanager\v0\spider.py", line 116, in sit
    json.dump(js.db,f,True)
  File "C:\Python27\lib\json\__init__.py", line 181, in dump
    for chunk in iterable:
  File "C:\Python27\lib\json\encoder.py", line 428, in _iterencode
    for chunk in _iterencode_dict(o, _current_indent_level):
  File "C:\Python27\lib\json\encoder.py", line 402, in _iterencode_dict
    for chunk in chunks:
  File "C:\Python27\lib\json\encoder.py", line 402, in _iterencode_dict
    for chunk in chunks:
  File "C:\Python27\lib\json\encoder.py", line 436, in _iterencode
    o = _default(o)
  File "C:\Python27\lib\json\encoder.py", line 178, in default
    raise TypeError(repr(o) + " is not JSON serializable")
TypeError: {'album': [u"Rooney Lost Album"], 'title': [u'The Kids
After Sunset'], 'artist': [u'Rooney']} is not JSON serializable

С ключом для этой конкретной записи песни является

Rooney|Rooney Lost Album|The Kids After Sunset|The Kids After Sunset.itunes.mp3

(формат id немного громоздкий, я могу в конечном итоге хешировать это...)

Итак, я попытался

json.dumps({'album': [u"Rooney Lost Album"], 'title': [u'The Kids
After Sunset'], 'artist': [u'Rooney']})

который работал нормально, как и

json.dumps({"Rooney|Rooney Lost Album|The Kids After Sunset|The Kids
After Sunset.itunes.mp3":""})

И затем я попробовал это:

rooney = "Rooney|Rooney Lost Album|The Kids After Sunset|The Kids
    After Sunset.itunes.mp3"
json.dumps({rooney:js.db['songsbyid'][rooney]})

Ошибка с ошибкой типа снова.

Почему этот объект не работает с json.dump? У меня много других объектов с ключами, содержащими трубы "|" и апострофы ""... На данный момент у меня нет возможности проверить это, если я опубликую маринованную версию объекта базы данных?

Дополнительные примечания

  • Результирующий объект, расположенный ниже json.dumps, прекрасен, поэтому мне интересно, каким образом проблема связана с размером базы данных?

      

    {Rooney: js.db [ 'songsbyid'] [Rooney]}     { "Руни | Затерянный альбом Руни | Дети после заката | Дети     After Sunset.itunes.mp3": {'album': [u "Rooney Lost Album" ],     'title': [u'The Kids After Sunset], 'artist': [u'Rooney '}}}

      
  • Если я исключил песню, переименовав расширение, чтобы script игнорировал его, другая произвольная песня вызывает ту же ошибку. Я переименовал и исключил эту новую песню и наткнулся на другую песню... Я не знаю, сколько там.

  • Я изменил свою программу, чтобы просканировать следующий самый дальний подкаталог, содержащий исходную песню о проблемах, а json.dump поднял TypeError на совершенно другую песню...

4b9b3361

Ответ 1

Потому что это не словарь; это другой тип отображения, который выглядит как словарь. Используйте type() для проверки. Передайте его dict(), чтобы получить от него настоящий словарь.

Ответ 2

Я написал класс для нормализации данных в моем словаре. "Элемент" в классе NormalizeData ниже должен иметь тип dict. И вам нужно заменить в __iterate() либо свой пользовательский объект класса, либо любой другой тип объекта, который вы хотите нормализовать.

class NormalizeData:

    def __init__(self, element):
        self.element = element

    def execute(self):
        if isinstance(self.element, dict):
            self.__iterate()
        else:
            return

    def __iterate(self):
        for key in self.element:
            if isinstance(self.element[key], <ClassName>):
                self.element[key] = str(self.element[key])

            node = NormalizeData(self.element[key])
            node.execute()