Python列表理解的优化

Python列表理解的优化,python,Python,以上是我的理解清单。初始函数和filter子句调用getattr两次。Python会运行两次,还是会在知道可以在第一次调用后缓存结果的情况下对计算进行内部优化 如果Python不进行优化,我如何重写它以更快地运行?Python将运行getattr两次——它不进行任何优化(毕竟,它如何知道第一个属性fetch不会更改第二个属性的值?) 要优化查询,可以分两个阶段进行。第一阶段使用生成器表达式计算值,第二阶段过滤这些值: [getattr(x, contact_field_map[communica

以上是我的理解清单。初始函数和filter子句调用getattr两次。Python会运行两次,还是会在知道可以在第一次调用后缓存结果的情况下对计算进行内部优化


如果Python不进行优化,我如何重写它以更快地运行?

Python将运行
getattr
两次——它不进行任何优化(毕竟,它如何知道第一个属性fetch不会更改第二个属性的值?)

要优化查询,可以分两个阶段进行。第一阶段使用生成器表达式计算值,第二阶段过滤这些值:

[getattr(x, contact_field_map[communication_type])
                            for x in curr_role_group.contacts if
                            getattr(x, contact_field_map[communication_type])]

Python将运行两次
getattr
——它不会进行任何优化(毕竟,它怎么知道第一个属性fetch不会更改第二个属性的值?)

要优化查询,可以分两个阶段进行。第一阶段使用生成器表达式计算值,第二阶段过滤这些值:

[getattr(x, contact_field_map[communication_type])
                            for x in curr_role_group.contacts if
                            getattr(x, contact_field_map[communication_type])]
尝试一下:

gen = (getattr(x, contact_field_map[communication_type])
                        for x in curr_role_group.contacts)
result = [item for item in gen if item]
例如,代替

[res for x in curr_role_group.contacts 
     for res in [getattr(x, contact_field_map[communication_type])] if res]
[i**2表示范围(10)内的i,如果i**2<10]
输出:[0,1,4,9]
你能行

[i**2 for i in range(10) if i**2 < 10]
Out: [0, 1, 4, 9]
[res for i in range(10)如果res<10,[i**2]中的res
输出:[0,1,4,9]
在这里,您只计算一次
i**2

试试看:

gen = (getattr(x, contact_field_map[communication_type])
                        for x in curr_role_group.contacts)
result = [item for item in gen if item]
例如,代替

[res for x in curr_role_group.contacts 
     for res in [getattr(x, contact_field_map[communication_type])] if res]
[i**2表示范围(10)内的i,如果i**2<10]
输出:[0,1,4,9]
你能行

[i**2 for i in range(10) if i**2 < 10]
Out: [0, 1, 4, 9]
[res for i in range(10)如果res<10,[i**2]中的res
输出:[0,1,4,9]

在这里,您只计算一次
i**2

你能用发电机来处理整个事情吗?比如:

[res for i in range(10) for res in [i**2] if res < 10]
Out: [0, 1, 4, 9]

你能用发电机来做整个事情吗?比如:

[res for i in range(10) for res in [i**2] if res < 10]
Out: [0, 1, 4, 9]

根据经验,Python从不试图变得聪明——很有可能有人试图变得更聪明并打破假设。例如,
getattr
可以调用具有副作用的被覆盖的
\uuu getattr\uuuu
。另一条经验法则是,Python的内置程序速度很快,进行微优化是不值得的。除非您已经分析了代码并在这里看到瓶颈,否则不要麻烦。或者更常见的情况是,调用
\uu getattr\uu
,调用
@property
我没有考虑getattr可能有副作用。相关:。根据经验,Python从不试图变得聪明——很有可能有人试图变得更聪明并打破假设。例如,
getattr
可以调用具有副作用的被覆盖的
\uuu getattr\uuuu
。另一条经验法则是,Python的内置程序速度很快,进行微优化是不值得的。除非你已经分析了你的代码并在这里看到了瓶颈,否则不要麻烦了。或者更常见的是,调用
\uu getattr\uu
,调用
@property
,我没有考虑到getattr可能会有副作用。相关:。创建列表(即使只有一个元素)与简单操作相比,成本应该相当高。你计时了吗?使用生成器而不是列表有显著区别吗?@MisterMiyagi你是对的,这可能是对getattr的过度使用。如果您有一个代价高昂的函数,并且希望减少对该函数的调用次数,那么这是有意义的。对于
i**2
,两个答案都比原始答案慢。对于需要一段时间的操作,发电机稍微快一点。太好了,感谢您的测试和计时!看起来
list
开销真的可以忽略不计。与简单操作相比,创建列表(即使只有一个元素)的成本应该相当高。你计时了吗?使用生成器而不是列表有显著区别吗?@MisterMiyagi你是对的,这可能是对getattr的过度使用。如果您有一个代价高昂的函数,并且希望减少对该函数的调用次数,那么这是有意义的。对于
i**2
,两个答案都比原始答案慢。对于需要一段时间的操作,发电机稍微快一点。太好了,感谢您的测试和计时!似乎
列表
开销真的可以忽略不计。整个集合可以压缩为一个生成器表达式。请参阅@mgilson的解决方案整个集合可以压缩为生成器表达式。参见@mgilson的解决方案