Однострочник, чтобы проверить, дает ли итератор хотя бы один элемент? - PullRequest
82 голосов
/ 25 июня 2010

В настоящее время я делаю это:

try:
    something = iterator.next()
    # ...
except StopIteration:
    # ...

Но мне бы хотелось выражение, которое я могу поместить в простое выражение if. Есть ли что-нибудь встроенное, что сделало бы этот код менее неуклюжим?

any() возвращает False, если итерация пуста, но потенциально она будет перебирать все элементы, если это не так. Мне нужно только проверить первый пункт.


Кто-то спрашивает, что я пытаюсь сделать. Я написал функцию, которая выполняет запрос SQL и выдает его результаты. Иногда, когда я вызываю эту функцию, я просто хочу узнать, возвратил ли запрос что-нибудь и принять решение на основе этого.

Ответы [ 8 ]

121 голосов
/ 25 июня 2010

any не выйдет за пределы первого элемента, если он True. Если итератор выдаст что-то неверное, вы можете написать any(True for _ in iterator).

33 голосов
/ 25 июня 2010

В Python 2.6+, если имя sentinel связано со значением, которое итератор не может дать,

if next(iterator, sentinel) is sentinel:
    print('iterator was empty')

Если вы не знаете, что итератор может дать, сделайтеваш собственный страж (например, в верхней части вашего модуля) с

sentinel = object()

В противном случае вы можете использовать в роли стража любое значение, которое вы «знаете» (исходя из соображений приложения), что итератор можетвозможно не даст.

19 голосов
/ 25 июня 2010

Это не совсем чётко, но показывает способ упаковать его в функцию без потерь:

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

Это не совсем питонно, и для конкретных случаев, возможно, есть более лучшие (но менее общие) решения, такие как next default.

first = next(iter, None)
if first:
  # Do something

Это не является общим, потому что None может быть допустимым элементом во многих итерациях.

6 голосов
/ 25 июня 2010

вы можете использовать:

if zip([None], iterator):
    # ...
else:
    # ...

, но это не обязательно для читателя кода

2 голосов
/ 06 марта 2018

А как же:

In [1]: i=iter([])

In [2]: bool(next(i,False))
Out[2]: False

In [3]: i=iter([1])

In [4]: bool(next(i,False))
Out[4]: True
0 голосов
/ 06 февраля 2015

Немного поздно, но ... Вы можете превратить итератор в список, а затем поработать с этим списком:

# 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.
0 голосов
/ 25 июня 2010

Это оболочка итератора избыточного количества, которая обычно позволяет проверить, есть ли следующий элемент (путем преобразования в логическое значение)Конечно довольно неэффективно.

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]
0 голосов
/ 25 июня 2010

__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)).
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...