能否通过单循环同时生成同一对象集合的两个属性列表?
解决方案
你写的a, b = [foo.a, foo.b for foo in foo]这种写法行不通,因为这个列表推导式会生成类似[obj1_a, obj1_b, obj2_a, obj2_b,...]的一维列表,直接赋值给a,b会因元素数量不匹配报错。
要实现一行代码完成需求,且只遍历一次对象集合,可以用zip(*...)配合生成器表达式:
# 建议把对象集合命名为foo_collection,避免和单个对象变量名foo混淆 a, b = map(list, zip(*((foo.a, foo.b) for foo in foo_collection)))
原理说明:
((foo.a, foo.b) for foo in foo_collection)是生成器,逐个产出每个对象的a和b属性组成的元组,比如(obj1.a, obj1.b), (obj2.a, obj2.b)...zip(*...)会把这些元组“解包”并聚合:将所有元组的第一个元素(所有a属性)聚合成一个迭代器,第二个元素(所有b属性)聚合成另一个迭代器map(list,...)把zip返回的元组迭代器转换成列表,最终赋值给a和b
如果可以接受元组类型(不需要列表),还能简化成:
a, b = zip(*((foo.a, foo.b) for foo in foo_collection))
这种写法的优势是只遍历一次对象集合,当集合元素数量较多时,比原来两次独立列表推导式的效率更高。
内容的提问来源于stack exchange,提问作者Armangh
相关产品推荐
相关产品推荐

