2

我正在尝试将 JSON 加载回对象中。“加载”方法似乎可以正常工作,但该对象似乎没有我期望的属性。

我该如何检查/检查我拥有的对象(这是基于 Web 的代码)。

  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 实际上来自 Google App Engine 中的 urlfetch 到使用此实用程序创建的 rest web 服务: http ://code.google.com/p/appengine-rest-服务器。正在使用以下定义从数据存储中检索数据:

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

谢谢,尼尔

更新#1:基本上我试图将 JSON 反序列化回一个对象。理论上它是从一个对象序列化的,我现在想把它放回一个对象中。也许更好的问题是如何做到这一点?

更新#2:我试图将一个复杂的程序抽象为几行代码,所以我在“伪编码”中犯了一些错误,以便在此处发布。

这是一个更好的代码示例,现在从我可以在 PC 上运行的网站中取出。

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'}

我有更多的微软背景,所以当我听到序列化/反序列化时,我想从一个对象到一个字符串,然后从一个字符串回到一个对象。因此,如果我序列化为 JSON,然后反序列化,我会得到什么,字典、列表或对象?实际上,我从 REST webmethod 获取 JSON,这是代表我为我序列化我的对象。

理想情况下,我想要一个与上面的订阅者类匹配的订阅者对象,理想情况下,我不想编写一次性自定义代码(即特定于“订阅者”的代码),因为我想做同样的事情与其他数十个课程。如果我必须编写一些自定义代码,我将需要通用地编写它,以便它适用于任何类。

更新#3:这是为了解释更多为什么我认为这是一个必要的工具。我正在编写一个巨大的应用程序,可能在 Google App Engine (GAE) 上。我们倾向于 REST 架构有几个原因,但其中一个原因是我们的 Web GUI 应该通过 REST Web 层访问数据存储。(我更习惯于 SOAP,所以切换到 REST 本身就是一个小挑战)。因此,获取和更新数据的经典方法之一是通过业务或数据层。通过使用上面提到的 REST 实用程序,我可以选择 XML 或 JSON。我希望在我们开发大型应用程序之前做一个小型的工作原型)。然后,假设我们有一个成功的应用程序,GAE 将它的价格翻了一番。然后我们可以只重写数据层,使用我们的 Python/Django 用户层(Web 代码),并在 Amazon 或其他地方运行它。

如果我要做所有这些,为什么我希望一切都是字典对象。我不想拥有成熟的阶级结构的力量吗?接下来的技巧之一是某种对象关系映射 (ORM),因此我们不必公开我们的确切数据表,而是更多的逻辑层。

我们还希望向可能使用任何语言的付费用户公开一个 RESTful API。对于他们来说,他们可以使用 XML 或 JSON,他们不会使用这里讨论的序列化例程。

4

3 回答 3

4

json 只编码字符串、浮点数、整数、javascript 对象(python 字典)和列表。

您必须创建一个函数来将返回的字典转换为一个类,然后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. 我没有使用simplejsonYMMV 的经验,但我听说它们是相同的。

请注意,尽管两个订阅者对象的值相同,但生成的对象却不同。这可以通过记忆decode_from_dict课程来解决。

于 2010-09-15T03:07:52.630 回答
3

results在您的代码段中是一个字典,而不是一个字符串,因此json.loads会引发异常。如果这是固定的,subitem则内部循环中的每个都是一个元组,因此尝试将其添加到字符串中会引发另一个异常。我猜你已经简化了你的代码,但是这两种类型的错误应该已经表明你简化了太多(而且不正确)。为什么不使用(同样简化的)工作片段,以及您想要的实际字符串,json.loads而不是可能无法重现您的问题的字符串?该行动方案将使您容易为您提供帮助。

除了查看实际的字符串,并显示一些明显的信息,例如type(subscriber),很难根据明显损坏的代码和如此不充分的信息提供更多帮助:-(。

编辑:在“update2”中,OP 说

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

......它还能显示什么,祈祷?!您将键打印为字符串,然后将值打印为字符串——键字符串,值是另一个字典,所以它当然是“字符串化”的(JSON 中的所有字符串都是 Unicode——就像在 C# 中一样或 Java,你说你来自 MSFT 背景,那么为什么这会让你感到惊讶呢?!)。 str(somedict),与 相同repr(somedict),显示repr键和值的 (用大括号括起来,冒号和逗号作为适当的分隔符)。

JSON,一种完全独立于语言的序列化格式,虽然最初以 Javascript 为中心,但完全不知道您希望看到哪些类(如果有的话)的实例(当然它不会,而且认为它可能会是荒谬的:如何如果它硬编码“类”的概念,它是否可能与语言无关,包括Javascript在内的许多语言甚至没有这个概念?!) - 所以它使用(用Python术语)字符串,数字、列表和字典(任何半体面的现代语言都可以拥有的四种非常基本的数据类型,至少在某些库中,如果没有嵌入到适当的语言中!)。当你json.loads成为一根弦时,你将永远得到上面四种数据类型的嵌套组合(所有字符串都是unicode,所有数字都是浮点数,顺便说一句;-)。

如果您不知道(并且不想通过某种任意约定或其他方式进行编码)正在序列化哪些类的实例,但在反序列化时绝对必须返回类实例(不仅仅是字典等),JSON 本身不能帮助你——元信息不可能出现在 JSON 序列化的字符串本身中。

如果您对四种基本类型没问题,并且只想查看一些您认为比相关基本类型的默认 Python 字符串打印“更漂亮”的打印结果,那么您必须编写自己的递归漂亮打印函数取决于您对“漂亮”的主观定义(我怀疑您是否pprint更喜欢 Python 自己的标准库模块,而不是您当前的结果;-)。

于 2010-09-14T05:03:48.003 回答
0

我的猜测是loads返回字典。要迭代其内容,请使用以下内容:

for key, value in subscriber.items():
    self.response.out.write("%s: %s" %(key, value))
于 2010-09-14T05:01:06.340 回答