我在订购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做到这一点?
答案 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您可以在我上面链接的属性文档中阅读的方法。