序言:我正在针对交付json的服务编写python api。
文件以json格式存储在磁盘上以缓存值。
API应该对JSON数据进行类访问,因此IDE和用户可以在运行前知道对象中有什么(只读)属性,同时也提供一些便利功能。
问:我有两种可能的实现方式,我想知道哪一个更好或“Python”。虽然我两者都喜欢,但如果你能想出更好的解决方案,我愿意提出建议。
第一个解决方案:定义和继承JSONWRAPPER,同时很好,它是冗长的和重复的。
class JsonDataWrapper:
def __init__(self, json_data):
self._data = json_data
def get(self, name):
return self._data[name]
class Course(JsonDataWrapper):
def __init__(self, data):
super().__init__(data)
self._users = {} # class omitted
self._groups = {} # class omitted
self._assignments = {}
@property
def id(self): return self.get('id')
@property
def name(self): return self.get('full_name')
@property
def short_name(self): return self.get('short_name')
@property
def users(self): return self._users
@users.setter
def users(self, data):
users = [User(u) for u in data]
for user in users:
self.users[user.id] = user
# self.groups = user # this does not make much sense without the rest of the code (It works, but that decision will be revised :D)
第二种解决方案:使用lambda来缩短语法。在短时间工作时,它看起来不太合适(见下面的edit1)。
def json(name): return property(lambda self: self.get(name))
class Group(JsonDataWrapper):
def __init__(self, data):
super().__init__(data)
self.group_members = [] # elements are of type(User). edit1, was self.members = []
id = json('id')
description = json('description')
name = json('name')
description_format = json('description_format')
(命名这个函数‘JSON’不是问题,因为我不在其中导入JSON)。
我有一个可能的第三个解决方案,我不能把我的头绕过来:重写属性Buffin,这样我就可以定义一个装饰器来封装返回的字段名用于查找:
@json # just like a property fget
def short_name(self): return 'short_name'
如果代码更好的话,可能会有点短。
不合格解决方案(IMHO):
JSON {de,En}编码器:杀死所有灵活性,不提供只读属性的手段
__{get,set}attr__
:在运行前无法确定属性。虽然它可以将self.get('id')
缩短为self['id']
它也会使底层json数据中没有属性的情况更加复杂。谢谢你的阅读!
编辑1:2016-07-20t08:26z
为了进一步澄清(@supersaiyan)为什么我不太喜欢第二个解决方案:
我觉得lambda函数与其他类语义完全断开了连接(这也是为什么它更短的原因:d)。我想我可以通过在代码中正确地记录决策来帮助自己更喜欢它。第一种解决方案对于每个理解
@property
含义的人来说都很容易理解,而不需要任何额外的解释。关于@supersaiyan的第二点评论:你的问题是,为什么我把
Group.members
作为属性放在这里?列表存储类型(用户)实体,可能不是您想象的那样,我更改了示例。JWODDER:下次我会用代码复查,不知道那是一件事。
(另外:我真的认为
Group.members
让你们中的一些人失望了,我编辑了代码使其更明显:组成员是将被添加到列表中的用户。The complete code is on github,虽然没有记录,但对某些人来说可能很有趣。记住:这都是WIP:d)
最佳答案
你考虑过使用元类吗?
class JsonDataWrapper(object):
def __init__(self, json_data):
self._data = json_data
def get(self, name):
return self._data[name]
class JsonDataWrapperMeta(type):
def __init__(self, name, base, dict):
for mbr in self.members:
prop = property(lambda self: self.get(mbr))
setattr(self, mbr, prop)
# You can use the metaclass inside a class block
class Group(JsonDataWrapper):
__metaclass__ = JsonDataWrapperMeta
members = ['id', 'description', 'name', 'description_format']
# Or more programmatically
def jsonDataFactory(name, members):
d = {"members":members}
return JsonDataWrapperMeta(name, (JsonDataWrapper,), d)
Course = jsonDataFactory("Course", ["id", "name", "short_name"])
关于python - 用JSON数据包装python类,哪个更好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38464302/