python que One-liner para verificar si un iterador produce al menos un elemento




que es un iterable en python (7)

Actualmente estoy haciendo esto:

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

Pero me gustaría una expresión que pueda colocar dentro de una simple declaración if . ¿Hay algo incorporado que haría que este código parezca menos torpe?

any() devuelve False si un iterable está vacío, pero posiblemente iterará sobre todos los ítems si no lo está. Solo lo necesito para verificar el primer artículo.

Alguien pregunta qué estoy tratando de hacer. He escrito una función que ejecuta una consulta SQL y arroja sus resultados. A veces, cuando llamo a esta función, solo quiero saber si la consulta arrojó algo y tomar una decisión basada en eso.


any no irá más allá del primer elemento si es verdadero. En caso de que el iterador arroje algo falso, puede escribir any(True for _ in iterator) .


En Python 2.6+, si el nombre sentinel está vinculado a un valor que el iterador no puede ceder,

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

Si no tiene idea de qué podría rendir el iterador, haga su propio centinela (por ejemplo, en la parte superior de su módulo) con

sentinel = object()

De lo contrario, podría usar, en el rol de centinela, cualquier valor que "conozca" (basado en consideraciones de la aplicación) que el iterador no puede ceder.


Qué pasa:

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

__length_hint__ estima la longitud de la list(it) - es un método privado, sin embargo:

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)).

Un poco tarde, pero ... Podría convertir el iterador en una lista y luego trabajar con esa lista:

# 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.

Esto no es realmente más limpio, pero muestra una forma de empaquetarlo en una función sin pérdidas:

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

Esto no es realmente pitónico, y para casos particulares, probablemente haya soluciones mejores (pero menos generales), como el next valor predeterminado.

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

Esto no es general porque Ninguno puede ser un elemento válido en muchos iterables.


puedes usar:

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

pero es un poco inexplorado para el lector de código





iterator