项目中有可能会碰到这样一种场景:
根据一个id,查询得到和id对应的完整数据信息存储对象,比如书籍id到书籍详细信息,用户id到用户详细信息等,详细信息字段可能包括几十甚至上百个数据字段,真正需要返回给调用方的字段实际上却只占其中一小部分,这是出于性能和带宽的考虑(甚至在有些场景中,处于隐私或者安全考虑,强制要求不能返回非协议定义的信息字段,比如第三方登录一般只返回用户昵称、性别等少量信息),一般会从详细的数据对象中抽取出所需要的信息组装一个新的简化对象。
今天碰到这样一个问题,需要将一个存储多个详细信息对象的list转化为一个简化对象的list返回给主调方,尝试了数种方法后,通过使用列表推导、字典推导以及getattr内置函数这三者,用数行代码即达到了这一目的,
原始数据结构定义:
class detail_info(object): def __init(self): self.id = ‘‘ self.title = ‘‘ self.name = ‘‘ self.url = ‘‘ self.avatar = ‘‘ self.p1 = None self.p2 = None self.p3 = None self.p4 = None self.p5 = None self.p6 = None self.p7 = None self.p8 = None ...
实际所需要返回的信息字段为id,title,url和p1,放入一个字典即可,如下为针对一个长度为5的list执行的结果,经过字典推导+列表推导,并通过getattr动态获取类的属性值,两行代码即实现了将所需字段抽取出来形成一个以dict为元素的list。
>>> needed_keys = [‘id‘, ‘title‘, ‘url‘, ‘p1‘] >>> [{k: getattr(x, k) for k in needed_keys} for x in alist] [{‘url‘: ‘url_0‘, ‘p1‘: ‘p1_0‘, ‘id‘: ‘id_0‘, ‘title‘: ‘title_0‘}, {‘url‘: ‘url_1‘, ‘p1‘: ‘p1_1‘, ‘id‘: ‘id_1‘, ‘title‘: ‘title_1‘}, {‘url‘: ‘url_2‘, ‘p1‘: ‘p1_2‘, ‘id‘: ‘id_2‘, ‘title‘: ‘title_2‘}, {‘url‘: ‘url_3‘, ‘p1‘: ‘p1_3‘, ‘id‘: ‘id_3‘, ‘title‘: ‘title_3‘}, {‘url‘: ‘url_4‘, ‘p1‘: ‘p1_4‘, ‘id‘: ‘id_4‘, ‘title‘: ‘title_4‘}, {‘url‘: ‘url_5‘, ‘p1‘: ‘p1_5‘, ‘id‘: ‘id_5‘, ‘title‘: ‘title_5‘}]
如果要直接返回一个类似如下的简化结构:
class SimpleInfo(object): def __init__(self): self.id = ‘‘ self.title = ‘‘ self.url = ‘‘ self.p1 = None
也只需要预先定义一个和alist等长的存储SimpleInfo结构的等长blist,组合zip函数的使用,稍加改动即可:
>>> blist = [SimpleInfo() for i in range(0, len(alist))] >>> needed_keys = [‘id‘, ‘title‘, ‘url‘, ‘p1‘] >>> [[setattr(y, k, getattr(x, k)) for k in needed_keys] for x, y in zip(alist,blist)] [[None, None, None, None], [None, None, None, None], [None, None, None, None], [None, None, None, None], [None, None, None, None]]
>>> blist[0].__dict__
{‘url‘: ‘url_0‘, ‘p1‘: ‘p1_0‘, ‘id‘: ‘id_0‘, ‘title‘: ‘title_0‘}
这里列表推导的代码使用setattr对blist中的SimpleInfo对象属性赋值,由于函数返回值为None,所以列表推导的结果是一个元素为None的list,通过查看blist[0]的信息,可以确认实际要赋值的属性已经通过setattr赋值给blist中对应的对象了。