Question Comment puis-je vérifier si une liste est vide?


Par exemple, si transmis les éléments suivants:

a = []

Comment puis-je vérifier si a est vide?


2718
2017-09-10 06:20


origine


Réponses:


if not a:
  print("List is empty")

Utiliser le booléen implicite de la liste vide est assez pythonique.


3886
2017-09-10 06:28



La façon pythonique de le faire est de Guide de style PEP 8 (où Oui signifie "recommandé" et Non signifie "non recommandé"):

Pour les séquences, (chaînes, listes, tuples), utilisez le fait que les séquences vides sont fausses.   

Oui: if not seq:
     if seq:

Non:  if len(seq):
     if not len(seq):

862
2017-09-10 10:33



Je le préfère explicitement:

if len(li) == 0:
    print('the list is empty')

De cette façon, il est clair à 100% que li est une séquence (liste) et nous voulons tester sa taille. Mon problème avec if not li: ... est que cela donne la fausse impression que li est une variable booléenne.


517
2017-09-05 00:30



D'autres personnes semblent généraliser la question au-delà des listes, alors j'ai pensé que j'ajouterais un autre type de séquence que beaucoup de gens pourraient utiliser, d'autant plus que c'est le premier google hit pour "python test empty array" .

D'autres méthodes ne fonctionnent pas pour les tableaux numpy

Vous devez faire attention avec les tableaux numpy, parce que d'autres méthodes qui fonctionnent bien pour lists ou d'autres conteneurs standard échouent pour des tableaux numpy. J'explique pourquoi ci-dessous, mais en bref, le méthode préférée est d'utiliser size.

Le chemin "pythonique" ne fonctionne pas: Partie 1

La méthode "pythonic" échoue avec des tableaux numpy car numpy essaie de convertir le tableau en un tableau de boolle sable if x essaie d'évaluer tous ceux bools à la fois pour une sorte de valeur de vérité agrégée. Mais cela n'a aucun sens, alors vous obtenez un ValueError:

>>> x = numpy.array([0,1])
>>> if x: print("x")
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

Le chemin "pythonique" ne fonctionne pas: Partie 2

Mais au moins le cas ci-dessus vous dit qu'il a échoué. Si vous avez un tableau numpy avec exactement un élément, le if la déclaration fonctionnera, dans le sens où vous n'obtenez pas d'erreur. Cependant, si cet élément se trouve être 0 (ou 0.0, ou false, ...), la if déclaration entraînera incorrectement false:

>>> x = numpy.array([0,])
>>> if x: print("x")
... else: print("No x")
No x

Mais clairement x existe et n'est pas vide! Ce résultat n'est pas ce que tu voulais.

En utilisant len peut donner des résultats inattendus

Par exemple,

len( numpy.zeros((1,0)) )

renvoie 1, même si le tableau a zéro élément.

La manière numpythonique

Comme expliqué dans le scipy FAQ, la méthode correcte dans tous les cas où vous savez que vous avez un tableau numpy est d'utiliser if x.size:

>>> x = numpy.array([0,1])
>>> if x.size: print("x")
x

>>> x = numpy.array([0,])
>>> if x.size: print("x")
... else: print("No x")
x

>>> x = numpy.zeros((1,0))
>>> if x.size: print("x")
... else: print("No x")
No x

Si vous n'êtes pas sûr que ce soit un list, un tableau numpy, ou autre chose, vous pouvez combiner cette approche avec la réponse @dubiousjim donne pour s'assurer que le bon test est utilisé pour chaque type. Pas très "pythonique", mais il s'avère que numpy a intentionnellement cassé la pythonicité au moins dans ce sens.

Si vous devez faire plus que simplement vérifier si l'entrée est vide, et si vous utilisez d'autres fonctions numpy comme l'indexation ou les opérations mathématiques, il est probablement plus efficace (et certainement plus commun) de forcer l'entrée être un tableau numpy. Il y a quelques bonnes fonctions pour le faire rapidement - le plus important numpy.asarray. Cela prend votre entrée, ne fait rien si c'est déjà un tableau, ou enveloppe votre entrée dans un tableau s'il s'agit d'une liste, d'un tuple, etc., et le convertit éventuellement en votre choix dtype. Donc, c'est très rapide chaque fois que cela peut être, et cela garantit que vous venez de supposer que l'entrée est un tableau numpy. En général, nous n'utilisons que le même nom, car la conversion en tableau ne le fera pas en dehors du courant. portée:

x = numpy.asarray(x, dtype=numpy.double)

Cela fera le x.size vérifier le travail dans tous les cas je vois sur cette page.


208
2018-02-21 16:48



Une liste vide est elle-même considérée comme fausse dans les tests de valeurs vraies (voir documentation python):

a = []
if a:
     print "not empty"

@Daren Thomas

EDIT: un autre point contre les tests   la liste vide comme faux: qu'en est-il   polymorphisme? Vous ne devriez pas dépendre de   une liste étant une liste. Cela devrait juste   charlatan comme un canard - comment vas-tu   obtenir votre canardCollection à charlatan   '' Faux '' quand il n'a pas d'éléments?

Votre canardCollection devrait mettre en œuvre __nonzero__ ou __len__ donc le si a: fonctionnera sans problèmes.


103
2017-09-10 06:31



Patrick (accepté) réponse est correct: if not a: est la bonne façon de le faire. La réponse de Harley Holcombe est vrai que c'est dans le guide de style PEP 8. Mais ce qu'aucune des réponses n'explique, c'est pourquoi c'est une bonne idée de suivre l'idiome - même si vous trouvez personnellement que ce n'est pas assez explicite ou déroutant pour les utilisateurs de Ruby ou quoi que ce soit.

Le code Python et la communauté Python ont des idiomes très forts. Suivre ces idiomes rend votre code plus facile à lire pour tous ceux qui ont l'expérience de Python. Et quand vous violez ces idiomes, c'est un signal fort.

C'est vrai que if not a: ne distingue pas les listes vides de None, ou numérique 0, ou des tuples vides, ou des types de collection vides créés par l'utilisateur, ou des types vide non créés par l'utilisateur, ou un tableau NumPy simple élément agissant comme des scalaires avec des valeurs falsey, etc. Et parfois il est important d'être explicite à ce sujet. Et dans ce cas, vous savez quelle vous voulez être explicite, pour que vous puissiez tester exactement cela. Par exemple, if not a and a is not None: signifie "quoi que ce soit falsey sauf None", tandis que if len(a) != 0: signifie "seulement des séquences vides - et n'importe quoi d'autre qu'une séquence est une erreur ici", et ainsi de suite. En plus de tester exactement ce que vous voulez tester, cela indique également au lecteur que ce test est important.

Mais quand vous n'avez rien d'explicite, autre chose que if not a: induit le lecteur en erreur. Vous signalez quelque chose d'important quand ce n'est pas le cas. (Vous pouvez également rendre le code moins flexible, ou plus lent, ou peu importe, mais c'est moins important.) Et si vous habituellement tromper le lecteur comme ça, puis quand vous faire besoin de faire une distinction, il va passer inaperçu parce que vous avez été "pleurer loup" partout dans votre code.


81
2017-12-03 02:21



Le meilleur moyen de vérifier si une liste est vide

Par exemple, si transmis les éléments suivants:

a = []

Comment puis-je vérifier si un est vide?

Réponse courte:

Placez la liste dans un contexte booléen (par exemple, avec un if ou whiledéclaration). Il va tester False s'il est vide, et True autrement. Par exemple:

if not a:                           # do this!
    print('a is an empty list')

Appel à l'autorité

PEP 8, le guide de style Python officiel pour le code Python dans la bibliothèque standard de Python, affirme:

Pour les séquences, (chaînes, listes, tuples), utilisez le fait que les séquences vides sont fausses.

Yes: if not seq:
     if seq:

No: if len(seq):
    if not len(seq):

Nous devrions nous attendre à ce que le code de la bibliothèque standard soit aussi performant et correct que possible. Mais pourquoi est-ce le cas, et pourquoi avons-nous besoin de cette orientation?

Explication

Je vois souvent du code comme celui-ci de la part de programmeurs expérimentés qui découvrent Python:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

Et les utilisateurs de langages paresseux peuvent être tentés de le faire:

if a == []:                         # Don't do this!
    print('a is an empty list')

Ceux-ci sont corrects dans leurs autres langues respectives. Et ceci est même sémantiquement correct en Python.

Mais nous le considérons comme non-Pythonic parce que Python supporte ces sémantiques directement dans l'interface de l'objet de la liste via la coercition booléenne.

Du docs (et notez spécifiquement l'inclusion de la liste vide, []):

Par défaut, un objet est considéré comme vrai sauf si sa classe définit   soit un __bool__() méthode qui renvoie False ou un __len__() méthode   qui renvoie zéro, lorsqu'il est appelé avec l'objet. Voici la plupart des objets intégrés considérés comme faux:

  • constantes définies comme étant fausses: None et False.
  • zéro de tout type numérique: 0, 0.0, 0j, Decimal(0), Fraction(0, 1)
  • séquences vides et collections: '', (), [], {}, set(), range(0)

Et la documentation datamodel:

object.__bool__(self)

Appelé pour implémenter le test de valeur de vérité et l'opération intégrée bool(); devrait revenir False ou True. Lorsque cette méthode n'est pas définie,    __len__() est appelée, si elle est définie, et l'objet est considéré comme vrai si son résultat est différent de zéro. Si une classe ne définit ni __len__()   ni __bool__(), toutes ses instances sont considérées comme vraies.

et

object.__len__(self)

Appelé pour implémenter la fonction intégrée len(). Devrait retourner la longueur de l'objet, un entier> = 0. Aussi, un objet qui ne définit pas un __bool__() méthode et dont __len__() La méthode retourne zéro est considérée comme fausse dans un contexte booléen.

Donc, au lieu de cela:

if len(a) == 0:                     # Don't do this!
    print('a is an empty list')

ou ca:

if a == []:                     # Don't do this!
    print('a is an empty list')

Faites ceci:

if not a:
    print('a is an empty list')

Faire ce que Pythonic paye habituellement en performance:

Est-ce que ça rapporte? (Notez que moins de temps pour effectuer une opération équivalente est préférable :)

>>> import timeit
>>> min(timeit.repeat(lambda: len([]) == 0, repeat=100))
0.13775854044661884
>>> min(timeit.repeat(lambda: [] == [], repeat=100))
0.0984637276455409
>>> min(timeit.repeat(lambda: not [], repeat=100))
0.07878462291455435

Pour l'échelle, voici le coût de l'appel de la fonction et de la construction et du renvoi d'une liste vide, que vous pourriez soustraire des coûts des contrôles de vide utilisés ci-dessus:

>>> min(timeit.repeat(lambda: [], repeat=100))
0.07074015751817342

On voit ça non plus vérifier la longueur avec la fonction intégrée len par rapport à 0  ou vérifier contre une liste vide est beaucoup moins performant que d'utiliser la syntaxe intégrée du langage tel que documenté.

Pourquoi?

Pour le len(a) == 0 vérifier:

Le premier Python doit vérifier les globals pour voir si len est ombragé.

Ensuite, il doit appeler la fonction, charger 0, et faites la comparaison d'égalité en Python (au lieu de C):

>>> import dis
>>> dis.dis(lambda: len([]) == 0)
  1           0 LOAD_GLOBAL              0 (len)
              2 BUILD_LIST               0
              4 CALL_FUNCTION            1
              6 LOAD_CONST               1 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

Et pour le [] == []il doit construire une liste inutile et, encore une fois, faire l'opération de comparaison dans la machine virtuelle de Python (par opposition à C)

>>> dis.dis(lambda: [] == [])
  1           0 BUILD_LIST               0
              2 BUILD_LIST               0
              4 COMPARE_OP               2 (==)
              6 RETURN_VALUE

La méthode "Pythonic" est une vérification beaucoup plus simple et rapide puisque la longueur de la liste est mise en cache dans l'en-tête de l'instance d'objet:

>>> dis.dis(lambda: not [])
  1           0 BUILD_LIST               0
              2 UNARY_NOT
              4 RETURN_VALUE

Preuve de la source C et de la documentation

PyVarObject

Ceci est une extension de PyObject cela ajoute le ob_size champ. Ceci est seulement utilisé pour les objets qui ont une certaine notion de longueur. Ce type n'apparaît pas souvent dans l'API Python / C. Il correspond aux champs définis par l'expansion du PyObject_VAR_HEAD macro

De la source c dans Inclure / listobject.h:

typedef struct {
    PyObject_VAR_HEAD
    /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
    PyObject **ob_item;

    /* ob_item contains space for 'allocated' elements.  The number
     * currently in use is ob_size.
     * Invariants:
     *     0 <= ob_size <= allocated
     *     len(list) == ob_size

J'ai aimé faire des recherches et j'ai passé beaucoup de temps à préparer mes réponses. Si vous pensez que je laisse quelque chose, faites le moi savoir dans un commentaire.


80
2017-08-20 03:50