web-dev-qa-db-fra.com

Une ligne pour vérifier si un itérateur produit au moins un élément?

Actuellement, je fais ceci:

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

Mais je voudrais une expression que je puisse placer dans une simple instruction if. Y a-t-il quelque chose de intégré qui rendrait ce code moins maladroit?

any() renvoie False si un itérable est vide, mais il peut potentiellement parcourir tous les éléments s'il ne l'est pas. J'en ai seulement besoin pour vérifier le premier article.


Quelqu'un me demande ce que j'essaie de faire. J'ai écrit une fonction qui exécute une requête SQL et donne ses résultats. Parfois, lorsque j'appelle cette fonction, je veux simplement savoir si la requête a renvoyé quelque chose et prendre une décision en fonction de cela.

84
Bastien Léonard

any ne dépassera pas le premier élément s'il est vrai. Dans le cas où l'itérateur renvoie quelque chose de faux, vous pouvez écrire any(True for _ in iterator).

122
Jochen Ritzel

Dans Python 2.6+, si le nom sentinel est lié à une valeur que l'itérateur ne peut éventuellement pas fournir,

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

Si vous n'avez aucune idée de ce que l'itérateur pourrait éventuellement produire, créez votre propre sentinelle (par exemple en haut de votre module) avec

sentinel = object()

Sinon, vous pourriez utiliser, dans le rôle de sentinelle, toute valeur que vous "connaissez" (sur la base de considérations d'application) que l'itérateur ne peut éventuellement pas fournir.

34
Alex Martelli

Ce n'est pas vraiment plus propre, mais cela montre un moyen de l'intégrer dans une fonction sans perte:

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

Ce n'est pas vraiment Pythonic, et pour des cas particuliers, il existe probablement de meilleures solutions (mais moins générales), comme le suivant par défaut.

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

Ce n'est pas général car None peut être un élément valide dans de nombreux itérables.

19
Matthew Flaschen

vous pouvez utiliser:

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

mais c'est un peu non explicatif pour le lecteur de code

6
mykhal

Qu'en est-il de:

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
2
Neil