Использование понимания списка для поиска 1 элемента в списке?

#python #list-comprehension

#python #понимание списка

Вопрос:

У меня есть небольшой вопрос относительно лучших практик для 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, я беспокоюсь о масштабируемости и выставлении счетов во время выполнения функции.

Должен ли я продолжать использовать понимание списка так, как я собираюсь это сделать, или есть способ получше?

Комментарии:

1. Вы всегда можете пойти императивным путем и просто записать функцию.

2. Определенно, но я просто не знал, есть ли быстрый и одноразовый способ сделать это.

Ответ №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
  

Комментарии:

1. Этот последний комментарий заслуживает 10 голосов «за», время, которое я однажды потратил на отладку цикла, который таинственным образом завершился раньше, потому что какая-то совершенно не связанная функция next() глубоко в стеке вызовов не перехватила его…

2. Честно говоря, именно поэтому я люблю stackoverflow. Спасибо cha0site, я, скорее всего, приму это как ответ, но я собираюсь оставить его открытым еще немного. Я определенно ценю ответ!

3. Быстрый вопрос по этому поводу, хотя, как бы вы обернули StopIteration исключение?

4. @ThomasTaylor: Я добавил некоторую информацию об этом.

5. Я принял ваш ответ. Большое спасибо за ваше время @cha0site