通过python中类的一个列表中的值对JSON转储进行排序

时间:2015-04-15 21:30:53

标签: python json dictionary

我在订购JSON输出时遇到了一些麻烦。下面是Rolodex类,它包含两个列表条目和错误。现在输出格式正确,如下所示,但我对它的订购方式有疑问。

class Rolodex:
  def __init__(self):
    self.entries = []
    self.errors = []

class Entry:
  def __init__(self):
    color = None
    firstname = None
    lastname = None
    phonenumber = None
    zipcode = None

def encode_rolo(obj):
  if isinstance(obj, Entry):
    return obj.__dict__
  else:
    raise TypeError("Unserializable object {} of type {}".format(obj,type(obj)))

output.write(json.dumps(rolo.__dict__, sort_keys=True, indent=4, separators=(',', ': '), default=encode_rolo).encode('utf-8'))

这是输出(截断):

{
    "entries": [
        {
            "color": "aqua marine",
            "firstname": "Ria",
            "lastname": "Tillotson",
            "phonenumber": "196-910-5548",
            "zipcode": "97671"
        },
        {
            "color": "blue",
            "firstname": "Annalee",
            "lastname": "Loftis",
            "phonenumber": "905-329-2054",
            "zipcode": "97296"
        },
        ...

    ],
    "errors": [
        1,
        6,
        ...
    ]
}

如您所见,条目列表中的键排序很好。但我希望能够通过(姓氏,名字)自己订购条目。有没有办法用json.dumps做到这一点?

2 个答案:

答案 0 :(得分:2)

你可以在转换成json之前通过排序来实现它。

例如:

entries.sort(key=lambda e: e['lastname']+e['firstname'])

答案 1 :(得分:0)

如果我正确理解了这一点,那么您的问题仅仅是Rolodex.entries处于插入顺序,而不是按照您希望的名称排序。您可以将该属性设置为属性而不是当前属性的常规属性,并让setter在每次插入时对该属性进行排序。以下是:

class Rolodex(object):
    def __init__(self):
        self.errors = []
        self._entries = []

    @property
    def entries(self):
        self._entries.sort(key=lambda x: (x.lastname, x.firstname))
        return self._entries

这种方式的工作方式是您的条目列表实际存储在Rolodex._entries中,这是Rolodex实例的私有属性。现在,为了让Rolodex.entries按照您的意愿工作,我们将其设为property。这实质上意味着您定义了每次尝试访问条目时都应该运行的方法,当然包括json.dumps()。在这种特定情况下,我们会根据您的条件对您的类的私有条目列表进行排序,然后每次访问时都返回该列表。

请注意,您必须从object继承您的课程才能使用此功能(这是您使用new-style classes的方式),您应养成始终从object继承的习惯,无论如何。)

另请注意,此实现效率相当低,但是我能够提出的最易读和最容易理解。您很可能也不需要更好的性能 - 但如果我在这个问题上出错了,您应该查看bisect模块并使用它来有效插入列表中,并使用setter您可以在我上面链接的属性文档中阅读的方法。