如果你不指定它,那么(高效)列表理解是多少?

时间:2014-01-29 10:42:38

标签: python performance list-comprehension

In this question,我和一位认为是

的评论者发生争执
for t in threads:
    t.join()

会好于

[t.join() for t in threads]

抛开“滥用理解”的问题 - 我倾向于同意,但我想为此做一个单行:如何(in-)效率是我的版本(第二个)真的吗? Python总是/在我的情况下实现列表推导还是在内部使用生成器?

map(lambda t: t.join(), threads)会更有效吗?或者是否有另一种方法将函数应用于列表threads中的每个元素?

5 个答案:

答案 0 :(得分:7)

列表理解将始终生成列表对象,在这种情况下,所有t.join()次调用的返回值。因此,Python为您生成长度为None的{​​{1}}值列表。 Python永远不会尝试优化列表对象的创建。

使用len(threads)添加额外的堆栈推送时,使用map()也不会更有效。坚持使用明确的lambda循环。

真的,对于一系列的线程连接,在这里试图进行微优化是没有意义。 您正在损害非关键代码段的可读性。

换句话说,我完全赞同这位意见提供者。不要使用列表推导或for仅用于副作用,并且保存自己必须点击 ENTER 并创建两行代码。

引用Zen of Python

  
      
  • 可读性很重要。
  •   

答案 1 :(得分:1)

如果你想要一个单行代码,写一个排气功能,并将它与发电机表达结合使用:

def exhaust(iterator):
    for _ in iterator:
        pass

exhaust(t.join() for t in threads)

然后你没有支付所有列表存储的费用。

随意重命名exhaust更适合您使用的内容。

我已经看到这个列表理解滥用了很多,甚至在采访编码样本中,我们明确指示候选人在解决问题时避免无限的记忆增长。

答案 2 :(得分:1)

你可以制作一个符合你想要的foreach。我建议反对它,因为它不是一种正常的python做事方式。未经测试,但与此相符:

class foreach:
    def __init__(self, object_list):
        self.__object_list = object_list

    def __getattr__(self, name):
        def f(*args, **kwargs):
            for obj in self.__object_list:
                getattr(obj, name)(*args, **kwargs)
        return f


foreach(thread_list).join()

它几乎创建了一种代理对象,可以将任何带有任何参数的调用转发给所有对象。

(如果你在我的开发团队中这样做,我很可能会有一个很好的聊天,但它确实可以作为python中可能的例子)

答案 3 :(得分:1)

无赋值列表压缩比 for 循环更好的一种情况是在赋值 self 或类似 locals().items() 时:

[self.__setattr__(k, v) for k, v in locals().items() if k != 'self']

列表压缩有它们自己的作用域,并用这样的常规循环做同样的事情:

for k, v in locals().items():
    if k != 'self':
        setattr(self, k, v)

最终会同时分配 kv,因为它们在第一个循环后被添加到 locals()。虽然我更喜欢像这样将它与 __slots__ 结合使用:

[self.__setattr__(k, v) for k, v in locals().items() if k in self.cls.__slots__]

其中 self.clstype(self)self.__class__,在这种情况下,两者都需要相同的 if 语句,但即使在这种情况下,我仍然更喜欢列表压缩。

答案 4 :(得分:0)

如果你想要单行,为什么不做for t in threads: t.join()

对我来说似乎是最简单的解决方案,并且可能也是最快的(但实际上,加入线程的开销可能会让其他任何东西相形见绌)