Ответ 1
any
не будет превышать первый элемент, если он True. Если итератор дает что-то ложное, вы можете написать any(True for _ in iterator)
.
В настоящее время я делаю это:
try:
something = iterator.next()
# ...
except StopIteration:
# ...
Но я хотел бы выразить выражение, которое я могу разместить внутри простого оператора if
.
Есть ли что-нибудь встроенное, которое сделает этот код менее неуклюжим?
any()
возвращает False
, если итерабельность пуста, но она будет потенциально перебирать все элементы, если это не так.
Мне нужно только проверить первый элемент.
Кто-то спрашивает, что я пытаюсь сделать. Я написал функцию, которая выполняет SQL-запрос и дает результаты. Иногда, когда я вызываю эту функцию, я просто хочу знать, вернул ли запрос что-нибудь и принял решение на основе этого.
any
не будет превышать первый элемент, если он True. Если итератор дает что-то ложное, вы можете написать any(True for _ in iterator)
.
В Python 2.6+, если имя sentinel
привязано к значению, которое не может выполнить итератор,
if next(iterator, sentinel) is sentinel:
print('iterator was empty')
Если вы не знаете, что итератор может уступить, сделайте свой собственный сторожевой (например, в верхней части вашего модуля) с помощью
sentinel = object()
В противном случае вы можете использовать в роли сторожевого устройства любое значение, которое вы "знаете" (на основе соображений приложения), которое итератор не может дать.
Это не очень чистый, но он показывает способ пакетного преобразования в функцию без потерь:
def has_elements(iter):
from itertools import tee
iter, any_check = tee(iter)
try:
any_check.next()
return True, iter
except StopIteration:
return False, iter
has_el, iter = has_elements(iter)
if has_el:
# not empty
Это не действительно pythonic, и для отдельных случаев есть, вероятно, лучшие (но менее общие) решения, такие как next по умолчанию.
first = next(iter, None)
if first:
# Do something
Это не общий, потому что None может быть допустимым элементом во многих итерациях.
вы можете использовать:
if zip([None], iterator):
# ...
else:
# ...
но это немного неэффективно для считывателя кода
__length_hint__
оценивает длину list(it)
- это частный метод:
x = iter( (1, 2, 3) )
help(x.__length_hint__)
1 Help on built-in function __length_hint__:
2
3 __length_hint__(...)
4 Private method returning an estimate of len(list(it)).
Это оболочка итератора overkill, которая обычно позволяет проверить, есть ли следующий элемент (через преобразование в логическое). Конечно, довольно неэффективно.
class LookaheadIterator ():
def __init__(self, iterator):
self.__iterator = iterator
try:
self.__next = next (iterator)
self.__have_next = True
except StopIteration:
self.__have_next = False
def __iter__(self):
return self
def next (self):
if self.__have_next:
result = self.__next
try:
self.__next = next (self.__iterator)
self.__have_next = True
except StopIteration:
self.__have_next = False
return result
else:
raise StopIteration
def __nonzero__(self):
return self.__have_next
x = LookaheadIterator (iter ([]))
print bool (x)
print list (x)
x = LookaheadIterator (iter ([1, 2, 3]))
print bool (x)
print list (x)
Вывод:
False
[]
True
[1, 2, 3]
Немного поздно, но... Вы можете включить итератор в список, а затем работать с этим списком:
# Create a list of objects but runs out the iterator.
l = [_ for _ in iterator]
# If the list is not empty then the iterator had elements; else it was empty.
if l :
pass # Use the elements of the list (i.e. from the iterator)
else :
pass # Iterator was empty, thus list is empty.