我开始习惯于在Python中列出理解,但我担心我使用它有些不正确。我已经遇到了几次使用列表理解但是立即从生成的列表中获取第一个(也是唯一的)项目的场景。这是一个例子:
actor = [actor for actor in self.actors if actor.name==actorName][0]
(self.actors包含一个对象列表,我正试图找到一个具有特定(字符串)名称的名称,该名称位于actorName中。)
我正在尝试从列表中提取与我正在寻找的参数匹配的对象。这种方法不合理吗?悬挂[0]让我觉得有点不安全。
答案 0 :(得分:91)
您可以使用生成器表达式而不是next
。这也会更有效,因为没有创建中间列表,并且一旦找到匹配就会停止迭代:
actor = next(actor for actor in self.actors if actor.name==actorName)
正如senderle指出的那样,这种方法的另一个优点是,如果找不到匹配项,您可以指定默认值:
actor = next((actor for actor in self.actors if actor.name==actorName), None)
答案 1 :(得分:18)
如果你想参加可能很多的第一场比赛,next(...)
很棒。
但是如果你只想到一个,那就考虑一下防守:
[actor] = [actor for actor in self.actors if actor.name==actorName]
这总是扫描到最后,但与[0]
不同,如果有0个或多个匹配,则解构为[actor]
会引发ValueError。
也许更重要的是捕捉错误,这将你的假设传达给读者。
如果您想要0匹配的默认值,但仍然捕获> 1匹配:
[actor] = [actor for actor in self.actors if actor.name==actorName] or [default]
P.S。也可以在右侧使用生成器表达式:
[actor] = (actor for actor in self.actors if actor.name==actorName)
应该更有效率。您可以在左侧使用元组语法 - 看起来更加对称,但逗号很难看,也很容易错过恕我直言:
(actor,) = [actor for actor in self.actors if actor.name==actorName]
actor, = [actor for actor in self.actors if actor.name==actorName]
答案 2 :(得分:2)
This post有一个自定义find()
功能,效果很好,还有一个评论者也与this method based on generators相关联。基本上,听起来没有一个很好的方法可以做到这一点 - 但这些解决方案并不坏。
答案 3 :(得分:1)
我个人认为这是一个适当的循环。
actor = None
for actor in self.actors:
if actor.name == actorName:
break
它要长一点,但确实有一个优点就是一旦找到匹配就会停止循环。