【问题标题】:Using list comprehension for finding 1 element in a list?使用列表推导在列表中查找 1 个元素?
【发布时间】:2019-03-05 14:15:21
【问题描述】:

我有一个关于 Python 最佳实践的简短问题。我已经看到 lambda + filter 函数在列表理解中的使用,但我想知道是否有更简单的方法可以在列表中查找特定元素,而无需生成和迭代整个列表。

使用 AWS boto3 库,我正在使用列表推导查询各种 get_x() 函数:

[i['domainName'] for i in domain_names['items'] if re.search(r'\b'+domain_name, i['domainName'])].pop()

[i['id'] for i in usage_plans['items'] if i['name']==f'{self.service}Usage'].pop()

如果未找到项目,则会捕获 IndexError 并将其转发给用户。由于这是在 AWS Lambda 函数中,我担心函数的可扩展性和运行时计费。

我应该继续使用列表推导式,还是有更好的方法?

【问题讨论】:

  • 你总是可以用命令式的方式写出函数。
  • 当然可以,但我只是不知道是否有一种快速且一次性的方法。

标签: python list-comprehension


【解决方案1】:

如果您想避免遍历整个列表,您可以使用生成器推导而不是列表推导。例如:

next(i for i in range(0, 2**1000) if i % 2 == 1)

遍历整个范围需要一段时间,但使用生成器理解它是瞬时的。

请注意,如果它没有找到一个项目,您会得到一个StopIteration 异常而不是IndexError。您确实必须捕获它并将其包装在另一个异常中,因为通过堆栈传播的流浪 StopIteration 可能会导致奇怪的行为。

包装StopIteration 看起来像这样:

>>> try:
...   next(i for i in range(0, 100) if i % 2 == 3 )
... except StopIteration:
...   raise IndexError("Couldn't find item")
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
StopIteration

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
IndexError: Couldn't find item

请注意,您可以给next 一个默认值以返回而不是提高StopIteration

>>> print(next((i for i in range(0, 100) if i % 2 == 3), None))
None

【讨论】:

  • 后一条评论值得 10 票赞成,我曾经花时间调试一个神秘地提前完成的循环,因为调用堆栈深处的一些完全不相关的 next() 没有捕捉到它......跨度>
  • 老实说,这就是我喜欢 stackoverflow 的原因。谢谢cha0site,我很可能会接受这个作为答案,但我会让它打开一段时间。我非常感谢您的回复!
  • 关于这个问题的快速问题,您将如何包装StopIteration 异常?
  • @ThomasTaylor:我添加了一些相关信息。
  • 我接受了你的回答。非常感谢您抽出宝贵时间@cha0site
猜你喜欢
  • 1970-01-01
  • 2020-09-25
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2020-05-07
  • 1970-01-01
  • 2016-07-18
  • 1970-01-01
相关资源
最近更新 更多