用装饰器编码自定义对象 - Python
我想找一种方法,在Python中使用类装饰器把自定义对象转换成字典。这个装饰器可以让我指定哪些变量应该包含在最终的字典里。然后,我可以用这个字典通过json.dumps(custom_object_dict)
来转换成JSON格式。
换句话说,我的想法是有一个这样的@encoder
类装饰器:
@encoder(variables=['firstname', 'lastname'], objects=['professor'], lists=['students'])
class Course(Object):
def __init__(self, firstname, lastname, professor, students):
self.firstname = firstname
self.lastname = lastname
self.professor = professor
self.students = students
#instance of Course:
course = Course("john", "smith", Professor(), [Student(1), Student(2, "john")])
这个装饰器可以让我做类似下面的事情:
选项A:
json = json.dumps(course.to_dict())
选项B:
json = json.dumps(course.dict_representation)
...或者类似的东西
所以我的问题是:如何编写这个编码器,主要的要求有:
- 编码器只应该编码通过装饰器提供的变量
- 编码器应该能够编码其他对象(例如:课程里的教授,如果教授类也有
@encoder
装饰器的话) - 还应该能够编码其他对象的列表(例如:课程里的学生,前提是学生类也有
@encoder
装饰器)
我研究了不同的方法来实现这个功能(包括创建一个继承自json.JSONEncoder的类),但没有一个完全符合我的想法。有人能帮我吗?
提前谢谢大家!
1 个回答
2
也许可以像这样做(这只是一个快速的草图):
#! /usr/bin/python3.2
import json
class Jsonable:
def __init__ (self, *args):
self.fields = args
def __call__ (self, cls):
cls._jsonFields = self.fields
def toDict (self):
d = {}
for f in self.__class__._jsonFields:
v = self.__getattribute__ (f)
if isinstance (v, list):
d [f] = [e.jsonDict if hasattr (e.__class__, '_jsonFields') else e for e in v]
continue
d [f] = v.jsonDict if hasattr (v.__class__, '_jsonFields') else v
return d
cls.toDict = toDict
oGetter = cls.__getattribute__
def getter (self, key):
if key == 'jsonDict': return self.toDict ()
return oGetter (self, key)
cls.__getattribute__ = getter
return cls
@Jsonable ('professor', 'students', 'primitiveList')
class Course:
def __init__ (self, professor, students):
self.professor = professor
self.students = students
self.toBeIgnored = 5
self.primitiveList = [0, 1, 1, 2, 3, 5]
@Jsonable ('firstname', 'lastname')
class Student:
def __init__ (self, firstname, lastname, score = 42):
self.firstname = firstname
self.lastname = lastname
self.score = score
@Jsonable ('title', 'name')
class Professor:
def __init__ (self, name, title):
self.title = title
self.name = name
p = Professor ('Ordóñez', 'Dra')
s1 = Student ('Juan', 'Pérez')
s2 = Student ('Juana', 'López')
s3 = Student ('Luis', 'Jerez')
s4 = Student ('Luisa', 'Gómez')
c = Course (p, [s1, s2, s3, s4] )
print (json.dumps (c.jsonDict) )
你可能还想检查其他可迭代的对象,除了 list
之外,或者可以用 hasattr(v, __iter__) and not isinstance(v, str)
这样的方式来判断。