Как проверить загадочный десериализованный объект в Python - PullRequest
2 голосов
/ 14 сентября 2010

Я пытаюсь загрузить JSON обратно в объект. Метод «загрузки», кажется, работает без ошибок, но объект, кажется, не обладает ожидаемыми свойствами.

Как я могу осмотреть / осмотреть объект, который у меня есть (это веб-код).

  results = {"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}
  subscriber = json.loads(results)


  for item in inspect.getmembers(subscriber): 
     self.response.out.write("<BR>Item")
     for subitem in item: 
         self.response.out.write("<BR>&nbsp;SubItem=" + subitem)

Попытка выше вернула это:

   Item
     SubItem=__class__

Я не думаю, что это имеет значение, но для контекста: JSON на самом деле идет от urlfetch в Google App Engine, чтобы веб-сервис отдыха, созданный с помощью этой утилиты: http://code.google.com/p/appengine-rest-server. Данные извлекаются из хранилища данных с таким определением:

class Subscriber(db.Model):
    firstname    = db.StringProperty()
    lastname     = db.StringProperty()

Спасибо, Нил

Обновление № 1: В основном я пытаюсь десериализовать JSON обратно в объект. В теории это было сериализовано от объекта, и теперь я хочу вернуть его обратно в объект. Может быть, лучший вопрос, как это сделать?

Обновление № 2: я пытался абстрагировать сложную программу до нескольких строк кода, поэтому я сделал несколько ошибок в «псевдокодировании» ее для целей публикации здесь.

Вот лучший пример кода, теперь возьмите с сайта, где я могу работать на ПК.

results = '{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}}'
subscriber = json.loads(results)
for key, value in subscriber.items():
    print " %s: %s" %(key, value)

Вышеприведенное работает, то, что оно отображает, выглядит не более структурированным, чем сама строка JSON. Это отображает это: Подписчик: {u'lastname ': u'Walters', u'firstname ': u'Neal'}

У меня больше опыта в Microsoft, поэтому, когда я слышу сериализацию / десериализацию, я думаю перейти от объекта к строке и от строки к объекту. Итак, если я сериализую в JSON, а затем десериализую, что я получу, словарь, список или объект? На самом деле, я получаю JSON от веб-метода REST, который от моего имени сериализует мой объект для меня.

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

Обновление № 3: Это объясняет, почему я считаю, что это необходимый инструмент. Я пишу огромное приложение, вероятно, на Google App Engine (GAE). Мы склоняемся к архитектуре REST по нескольким причинам, но одна из них заключается в том, что наш веб-интерфейс должен получать доступ к хранилищу данных через веб-уровень REST. (Я гораздо больше привык к SOAP, поэтому переключение на REST само по себе является небольшой проблемой). Таким образом, один из классических способов получения и обновления данных - через бизнес-уровень или уровень данных. Используя упомянутую выше утилиту REST, я могу выбрать XML или JSON. Я надеюсь сделать небольшой рабочий прототип обоих, прежде чем мы разработаем огромное приложение). Тогда, предположим, у нас есть успешное приложение, и GAE удваивает его цены. Затем мы можем переписать только уровень данных, взять наш уровень пользователя Python / Django (веб-код) и запустить его на Amazon или в другом месте.

Если я собираюсь все это делать, то зачем мне все объекты словаря. Разве я не хотел бы иметь мощную классовую структуру? Одним из следующих приемов является своего рода объектно-реляционное отображение (ORM), так что мы не обязательно выставляем наши точные таблицы данных, а скорее на логическом уровне.

Мы также хотим предоставить RESTful API платным пользователям, которые могут использовать любой язык. Для них они могут использовать XML или JSON, и они не будут использовать процедуру сериализации, обсуждаемую здесь.

Ответы [ 3 ]

3 голосов
/ 14 сентября 2010

results в вашем фрагменте - это диктат, а не строка, поэтому json.loads вызовет исключение. Если это исправлено, то каждый subitem во внутреннем цикле является кортежем, поэтому попытка добавить его в строку, как вы делаете, вызовет еще одно исключение. Я предполагаю, что вы упростили свой код, но две ошибки типа уже должны показать, что вы упростили его слишком сильно (и неправильно). Почему бы не использовать (одинаково упрощенный) рабочий фрагмент и фактическую строку, которую вы хотите json.loads, вместо строки, которая не может воспроизвести вашу проблему? Этот курс действий поможет вам на 1011 * намного легче помочь.

Помимо просмотра реальной строки и отображения некоторой очевидной информации, такой как type(subscriber), трудно предложить гораздо больше помощи на основе этого явно некорректного кода и такой недостаточной информации: - (.

Редактировать : в "update2" ОП говорит

It displays this: Subscriber: {u'lastname': u'Walters', u'firstname': u'Neal'}

... и что еще это может показать, молись ?! Вы печатаете ключ в виде строки, затем значение в виде строки - ключ - это строка, а значение - это еще один атрибут, поэтому, конечно, он «stringified» (и все строки в JSON являются Unicode - как в C # или Java, и вы говорите, что пришли из MSFT, так почему это вас вообще удивляет ?!). str(somedict), идентично repr(somedict), показывает repr ключей и значений (с фигурными скобками вокруг него, двоеточиями и запятыми в качестве соответствующих разделителей).

JSON, полностью независимый от языка формат сериализации, хотя изначально он был основан на Javascript, не имеет абсолютно никакого представления о том, какие классы (если таковые имеются) вы ожидаете увидеть экземпляры ( курса это не так и просто абсурдно думать, что это возможно: как может быть независимым от языка, если жестко закодировать само понятие «класс», понятие, которое так много языков, включая Javascript, не • даже имеют ?!) - поэтому он использует (в терминах Python) строки, числа, списки и дикты (четыре очень простых типа данных, которые, как можно ожидать, будет у любого полуприличного современного языка, в хотя бы в какой-то библиотеке, если она не встроена в сам язык!). Когда вы json.loads строка, вы всегда получаете некоторую вложенную комбинацию из четырех указанных выше типов данных (все строки будут в кодировке Unicode, а все числа будут с плавающей запятой, кстати);

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

Если вы в порядке с четырьмя фундаментальными типами и просто хотите увидеть некоторые напечатанные результаты, которые вы считаете "более красивыми", чем печать по умолчанию на Python для основных типов данных типов, вам придется написать свой рекурсивный код Функция Pretty-Printing в зависимости от вашего субъективного определения «Pretty» (я сомневаюсь, что вам понадобится стандартный библиотечный модуль Python pprint больше, чем ваши текущие результаты; -).

3 голосов
/ 15 сентября 2010

json кодирует только строки, числа с плавающей запятой, целые числа, объекты javascript (python dicts) и списки.

Вам нужно создать функцию, чтобы превратить возвращаемый словарь в класс, а затем передать его в json.loads с помощью ключевого аргумента object_hook вместе со строкой json. Вот некоторый код, который подчеркивает это:

import json

class Subscriber(object):
    firstname = None
    lastname = None


class Post(object):
    author = None
    title = None


def decode_from_dict(cls,vals):
    obj = cls()
    for key, val in vals.items():
        setattr(obj, key, val)
    return obj


SERIALIZABLE_CLASSES = {'Subscriber': Subscriber,
                        'Post': Post}

def decode_object(d):
    for field in d:
        if field in SERIALIZABLE_CLASSES:
            cls = SERIALIZABLE_CLASSES[field]
            return decode_from_dict(cls, d[field])
    return d


results = '''[{"Subscriber": {"firstname": "Neal", "lastname": "Walters"}},
              {"Post": {"author": {"Subscriber": {"firstname": "Neal",
                                                  "lastname": "Walters"}}},
                        "title": "Decoding JSON Objects"}]'''
result = json.loads(results, object_hook=decode_object)
print result
print result[1].author

Это будет обрабатывать любой класс, который может быть создан без аргументов конструктора и для которого будет работать setattr.

Также здесь используется json. У меня нет опыта работы с simplejson, поэтому YMMV, но я слышал, что они идентичны.

Обратите внимание, что, хотя значения для двух объектов подписчика идентичны, полученные объекты не являются. Это можно исправить, запомнив класс decode_from_dict.

0 голосов
/ 14 сентября 2010

Я предполагаю, что loads возвращает словарь.Чтобы перебрать его содержимое, используйте что-то вроде:

for key, value in subscriber.items():
    self.response.out.write("%s: %s" %(key, value))
...