Я хочу использовать Python для преобразования данных JSON в объект Python.
Я получаю объекты данных JSON из API Facebook, которые я хочу сохранить в своей базе данных.
Мой текущий вид в Django (Python) ( request.POST
содержит JSON):
response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
Это прекрасно работает, но как мне обрабатывать сложные объекты данных JSON?
Не было бы намного лучше, если бы я мог как-то преобразовать этот объект JSON в объект Python для простоты использования?
dict
s - это слабый способ создания объектно-ориентированного программирования. Словари - очень плохой способ сообщить ожидания читателям вашего кода. Используя словарь, как вы можете четко и многократно указать, что некоторые пары словарь-значение требуются, а другие нет? Как насчет подтверждения того, что данное значение находится в допустимом диапазоне или задано? А как насчет функций, которые специфичны для типа объекта, с которым вы работаете (так называемые методы)? Словари удобны и универсальны, но слишком многие разработчики ведут себя так, как будто они забыли, что Python по какой-то причине является объектно-ориентированным языком.Ответы:
Вы можете сделать это в одну строку, используя
namedtuple
иobject_hook
:или, чтобы использовать это легко:
Если вы хотите, чтобы справиться с ключами, которые не являются хорошими именами атрибутов, проверить
namedtuple
«srename
параметр .источник
d.keys()
иd.values()
повторять в одном и том же порядке не гарантируется, но я ошибся. В документах говорится: «Если представления ключей, значений и элементов повторяются без внесения изменений в словарь, порядок элементов будет напрямую соответствовать». Полезно знать для таких маленьких, локальных блоков кода. Я бы добавил комментарий, чтобы явно предупредить разработчиков кода о такой зависимости.x._asdict()
, что может помочь в простых случаях.Ознакомьтесь с разделом « Специализирование декодирования объектов JSON» в
json
документации модуля . Вы можете использовать это для декодирования объекта JSON в определенный тип Python.Вот пример:
Обновить
Если вы хотите получить доступ к данным в словаре через модуль json, сделайте это:
Так же, как обычный словарь.
источник
Это не кодовый гольф, но вот мой самый короткий трюк, использующий
types.SimpleNamespace
в качестве контейнера для объектов JSON.По сравнению с ведущим
namedtuple
решением это:rename
опции и, вероятно, такое же ограничение на ключи, которые не являются действительными идентификаторами (используетсяsetattr
под обложками)Пример:
источник
@post_load
декоратором. marshmallow.readthedocs.io/en/latest/…from types import SimpleNamespace
и используйте:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
types.SimpleNamespace
к сожалению, не существует в 2.7).print_function
?Вы можете попробовать это:
Просто создайте новый объект и передайте параметры в виде карты.
источник
Вот быстрая и грязная альтернатива JSON Pickle
источник
Для сложных объектов вы можете использовать JSON Pickle
источник
jsonstruct originally a fork of jsonpickle (Thanks guys!). The key difference between this library and jsonpickle is that during deserialization, jsonpickle requires Python types to be recorded as part of the JSON. This library intends to remove this requirement, instead, requires a class to be passed in as an argument so that its definition can be inspected. It will then return an instance of the given class. This approach is similar to how Jackson (of Java) works.
'[{"name":"object1"},{"name":"object2"}]'
. Jsonpickle тоже не очень хорошо с этим справляется.Если вы используете Python 3.5+, вы можете использовать его
jsons
для сериализации и десериализации простых старых объектов Python:Вы также можете сделать
FbApiUser
наследствоjsons.JsonSerializable
для большей элегантности:Эти примеры будут работать, если ваш класс состоит из типов Python по умолчанию, таких как строки, целые числа, списки, даты и т. Д. Однако в
jsons
lib потребуются подсказки типов для пользовательских типов.источник
Если вы используете python 3.6+, вы можете использовать marshmallow-dataclass . Вопреки всем решениям, перечисленным выше, это и простой, и безопасный тип:
источник
TypeError: make_data_class() got an unexpected keyword argument 'many'
Улучшение Lovasoa очень хороший ответ.
Если вы используете Python 3.6+, вы можете использовать:
pip install marshmallow-enum
иpip install marshmallow-dataclass
Это просто и безопасно.
Вы можете преобразовать свой класс в строку-json и наоборот:
От объекта к струне Json:
От струны Джсон до объекта:
Определения классов:
источник
Я написал небольшую (де) сериализационную среду под названием any2any, которая помогает выполнять сложные преобразования между двумя типами Python.
В вашем случае, я полагаю, вы хотите преобразовать словарь (полученный с помощью
json.loads
) в сложный объектresponse.education ; response.name
, с вложенной структуройresponse.education.id
и т. Д. Так что именно для этого и создана эта структура. Документация пока не очень хорошая, но с ее помощьюany2any.simple.MappingToObject
вы сможете сделать это очень легко. Пожалуйста, спросите, нужна ли вам помощь.источник
Поскольку никто не дал такого ответа, как я, я опубликую его здесь.
Это надежный класс, который может легко конвертировать туда и обратно между json
str
иdict
что я скопировал из моего ответа на другой вопрос :источник
Немного изменив ответ @DS, чтобы загрузить из файла:
Одна вещь: это не может загружать предметы с номерами впереди. Как это:
Потому что "1_first_item" не является допустимым именем поля Python.
источник
В поисках решения я наткнулся на этот пост в блоге: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/
Он использует ту же технику, что и в предыдущих ответах, но с использованием декораторов. Еще одна вещь, которая мне показалась полезной, это то, что она возвращает типизированный объект в конце десериализации
Использование:
источник
Если немного расширить ответ DS, то если вам нужно, чтобы объект был изменяемым (это не namedtuple), вы можете использовать библиотеку recordclass вместо namedtuple:
Модифицированный объект может быть легко преобразован обратно в json с помощью simplejson :
источник
Если вы используете Python 3.6 или новее, вы можете взглянуть на squema - легкий модуль для статически типизированных структур данных. Это делает ваш код легко читаемым, в то же время обеспечивая простую проверку данных, преобразование и сериализацию без дополнительной работы. Вы можете думать об этом как о более сложной и самоуверенной альтернативе именованных кортежей и классов данных. Вот как вы можете использовать это:
источник
Я искал решение, которое бы работало
recordclass.RecordClass
, поддерживало вложенные объекты и работало как для сериализации json, так и для десериализации json.Расширяя ответ DS и расширяя решение от BeneStr, я пришел к следующему, которое, кажется, работает:
Код:
Использование:
источник
Приведенные здесь ответы не возвращают правильный тип объекта, поэтому я создал эти методы ниже. Они также терпят неудачу, если вы пытаетесь добавить больше полей в класс, который не существует в данном JSON:
источник
Python3.x
Наилучшим подходом, которого я мог достичь с помощью моих знаний, было это.
Обратите внимание, что этот код также обрабатывает set ().
Этот подход является общим, просто требуется расширение класса (во втором примере).
Обратите внимание, что я просто делаю это с файлами, но легко изменить поведение на свой вкус.
Однако это кодек.
Приложив немного больше работы, вы можете создать свой класс другими способами. Я предполагаю, что конструктор по умолчанию его создает, а затем обновляю класс dict.
редактировать
Проведя дополнительные исследования, я нашел способ обобщения без необходимости вызова метода регистра SUPERCLASS с использованием метакласса.
источник
Ты можешь использовать
где
Для общего, перспективного решения.
источник
Используйте
json
модуль ( новый в Python 2.6 ) илиsimplejson
модуль, который почти всегда установлен.источник