In this question,我和一位认为是
的评论者发生争执for t in threads:
t.join()
会好于
[t.join() for t in threads]
抛开“滥用理解”的问题 - 我倾向于同意,但我想为此做一个单行:如何(in-)效率是我的版本(第二个)真的吗? Python总是/在我的情况下实现列表推导还是在内部使用生成器?
map(lambda t: t.join(), threads)
会更有效吗?或者是否有另一种方法将函数应用于列表threads
中的每个元素?
答案 0 :(得分:7)
列表理解将始终生成列表对象,在这种情况下,所有t.join()
次调用的返回值。因此,Python为您生成长度为None
的{{1}}值列表。 Python永远不会尝试优化列表对象的创建。
使用len(threads)
添加额外的堆栈推送时,使用map()
也不会更有效。坚持使用明确的lambda
循环。
真的,对于一系列的线程连接,在这里试图进行微优化是没有意义。 您正在损害非关键代码段的可读性。
换句话说,我完全赞同这位意见提供者。不要使用列表推导或for
仅用于副作用,并且保存自己必须点击 ENTER 并创建两行代码。
- 可读性很重要。
答案 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)
最终会同时分配 k
和 v
,因为它们在第一个循环后被添加到 locals()
。虽然我更喜欢像这样将它与 __slots__
结合使用:
[self.__setattr__(k, v) for k, v in locals().items() if k in self.cls.__slots__]
其中 self.cls
是 type(self)
或 self.__class__
,在这种情况下,两者都需要相同的 if
语句,但即使在这种情况下,我仍然更喜欢列表压缩。
答案 4 :(得分:0)
如果你想要单行,为什么不做for t in threads: t.join()
?
对我来说似乎是最简单的解决方案,并且可能也是最快的(但实际上,加入线程的开销可能会让其他任何东西相形见绌)