282 votes

Comment fonctionnent les fonctions any et all de Python?

Je tente de comprendre le fonctionnement des fonctions intégrées Python any() et all().

Je tente de comparer les tuples afin que si une valeur est différente, cela renverra True et s'ils sont tous les mêmes, cela renverra False. Comment fonctionnent-ils dans ce cas pour renvoyer [False, False, False] ?

d est un defaultdict(list).

print d['Drd2']
# [[1, 5, 0], [1, 6, 0]]
print list(zip(*d['Drd2']))
# [(1, 1), (5, 6), (0, 0)]
print [any(x) and not all(x) for x in zip(*d['Drd2'])]
# [False, False, False]

À ma connaissance, ceci devrait afficher

# [False, True, False]

car (1,1) sont les mêmes, (5,6) sont différents et (0,0) sont les mêmes.

Pourquoi évalue-t-il à False pour tous les tuples ?


Voir <a href="https://stackoverflow.com/questions/1342601">Manière pythonique de vérifier si une condition est vraie pour un élément d'une liste</a> pour une utilisation pratique de <code>any</code>.

441voto

thefourtheye Points 56958

Vous pouvez grosso modo penser à any et all comme des séries d'opérateurs logiques or et and respectivement.

any

any retournera Vrai lorsqu'au moins un des éléments est Truthy. En savoir plus sur le Test de la valeur de vérité.

all

all retournera Vrai uniquement lorsque tous les éléments sont Truthy.

Table de vérité

+-----------------------------------------+---------+---------+
|                                         |   any   |   all   |
+-----------------------------------------+---------+---------+
| Toutes les valeurs sont vraies           |  Vrai   |  Vrai   |
+-----------------------------------------+---------+---------+
| Toutes les valeurs sont fausses          |  Faux   |  Faux   |
+-----------------------------------------+---------+---------+
| Une valeur vraie (toutes les autres sont fausses) |  Vrai   |  Faux  |
+-----------------------------------------+---------+---------+
| Une valeur fausse (toutes les autres sont vraies) |  Vrai   |  Faux  |
+-----------------------------------------+---------+---------+
| Iterable vide                           |  Faux   |  Vrai   |
+-----------------------------------------+---------+---------+

Note 1: Le cas de l'itérable vide est expliqué dans la documentation officielle, comme ceci

any

Retourne Vrai si un élément de l'itérable est vrai. Si l'itérable est vide, retourne Faux

Puisque aucun élément n'est vrai, il retourne Faux dans ce cas.

all

Retourne Vrai si tous les éléments de l'itérable sont vrais (ou si l'itérable est vide).

Puisque aucun élément n'est faux, il retourne Vrai dans ce cas.


Note 2:

Une autre chose importante à savoir sur any et all est qu'ils interrompront l'exécution dès qu'ils connaissent le résultat. L'avantage est que l'itérable entier n'a pas besoin d'être consommé. Par exemple,

>>> multiples_de_6 = (not (i % 6) for i in range(1, 10))
>>> any(multiples_de_6)
True
>>> list(multiples_de_6)
[Faux, Faux, Faux]

Ici, (not (i % 6) for i in range(1, 10) est une expression génératrice qui retourne `Vrai` si le nombre actuel entre 1 et 9 est un multiple de 6. `any` itère sur `multiples_de_6` et lorsqu'il rencontre `6`, il trouve une valeur Truthy, donc il retourne immédiatement `Vrai`, et le reste de `multiples_de_6` n'est pas itéré. C'est ce que nous voyons quand nous imprimons `list(multiples_de_6)`, le résultat de `7`, `8` et `9`.

``Cette excellente fonctionnalité est utilisée de manière très astucieuse dans cette réponse.


Avec cette compréhension de base, si nous regardons votre code, vous faites

any(x) et not all(x)

ce qui garantit qu'au moins une des valeurs est Truthy mais pas toutes. C'est pourquoi il retourne [Faux, Faux, Faux]. Si vous vouliez vraiment vérifier si les deux nombres ne sont pas identiques,

print [x[0] != x[1] for x in zip(*d['Drd2'])]``

57voto

Aaron Hall Points 7381

Comment les fonctions any et all de Python fonctionnent-elles ?

any et all prennent des itérables et renvoient True si tous (respectivement) les éléments sont True.

>>> any([0, 0.0, False, (), '0']), all([1, 0.0001, True, (False,)])
(True, True)            #   ^^^-- chaîne non vide équivalente à True
>>> any([0, 0.0, False, (), '']), all([1, 0.0001, True, (False,), {}])
(False, False)                                                #   ^^-- équivalent à False

Si les itérables sont vides, any renvoie False, et all renvoie True.

>>> any([]), all([])
(False, True)

Aujourd'hui, j'enseignais aux étudiants en classe comment utiliser all et any. Ils étaient surtout confus au sujet des valeurs de retour pour les itérables vides. En expliquant de cette façon, beaucoup de compréhensions ont émergé.

Comportement de raccourci

Les fonctions any et all cherchent un condition qui leur permet d'arrêter l'évaluation. Les premiers exemples nécessitaient d'évaluer le booléen pour chaque élément dans la liste entière.

(Notez que la liste littérale n'est pas elle-même évaluée de manière paresseuse - vous pourriez obtenir cela avec un Itérateur - mais c'est juste à des fins illustratives.)

Voici une implémentation Python de any et all :

def any(iterable):
    for i in iterable:
        if i:
            return True
    return False # pour un itérable vide, any renvoie False!

def all(iterable):
    for i in iterable:
        if not i:
            return False
    return True  # pour un itérable vide, all renvoie True!

Évidemment, les implémentations réelles sont écrites en C et sont beaucoup plus performantes, mais vous pourriez substituer le code ci-dessus et obtenir les mêmes résultats pour le code dans cette (ou toute autre) réponse.

all

all vérifie que les éléments soient False (pour pouvoir renvoyer False), puis renvoie True si aucun d'entre eux n'était False.

>>> all([1, 2, 3, 4])                 # doit tester jusqu'à la fin!
True
>>> all([0, 1, 2, 3, 4])              # 0 est False dans un contexte booléen!
False  # ^-- s'arrête ici !
>>> all([])
True   # arrive à la fin, donc True!

any

La façon dont any fonctionne est qu'elle vérifie que les éléments soient True (pour pouvoir renvoyer True), puis renvoie False si aucun d'entre eux n'était True.

>>> any([0, 0.0, '', (), [], {}])     # doit tester jusqu'à la fin!
False
>>> any([1, 0, 0.0, '', (), [], {}])  # 1 est True dans un contexte booléen!
True   # ^-- s'arrête ici !
>>> any([])
False   # arrive à la fin, donc False!

Je pense que si vous gardez à l'esprit le comportement de raccourci, vous comprendrez intuitivement comment elles fonctionnent sans avoir besoin de consulter une table de vérité.

Preuves du comportement de raccourci de all et any:

Tout d'abord, créons un itérateur bruyant :

def noisy_iterator(iterable):
    for i in iterable:
        print('yielnd ' + repr(i))
        yield i

et maintenant itérons simplement sur les listes de manière bruyante, en utilisant nos exemples :

>>> all(noisy_iterator([1, 2, 3, 4]))
yielnd 1
yielnd 2
yielnd 3
yielnd 4
True
>>> all(noisy_iterator([0, 1, 2, 3, 4]))
yielnd 0
False

Nous pouvons voir que all s'arrête au premier check de booléen False.

Et any s'arrête au premier check de booléen True :

>>> any(noisy_iterator([0, 0.0, '', (), [], {}]))
yielnd 0
yielnd 0.0
yielnd ''
yielnd ()
yielnd []
yielnd {}
False
>>> any(noisy_iterator([1, 0, 0.0, '', (), [], {}]))
yielnd 1
True

La source

Examinons la source pour confirmer ce qui précède.

Voici la source pour any:

static PyObject *
builtin_any(PyObject *module, PyObject *iterable)
{
    PyObject *it, *item;
    PyObject *(*iternext)(PyObject *);
    int cmp;

    it = PyObject_GetIter(iterable);
    if (it == NULL)
        return NULL;
    iternext = *Py_TYPE(it)->tp_iternext;

    for (;;) {
        item = iternext(it);
        if (item == NULL)
            break;
        cmp = PyObject_IsTrue(item);
        Py_DECREF(item);
        if (cmp < 0) {
            Py_DECREF(it);
            return NULL;
        }
        if (cmp > 0) {
            Py_DECREF(it);
            Py_RETURN_TRUE;
        }
    }
    Py_DECREF(it);
    if (PyErr_Occurred()) {
        if (PyErr_ExceptionMatches(PyExc_StopIteration))
            PyErr_Clear();
        else
            return NULL;
    }
    Py_RETURN_FALSE;
}

Et voici la source pour all:

static PyObject *
builtin_all(PyObject *module, PyObject *iterable)
{
    PyObject *it, *item;
    PyObject *(*iternext)(PyObject *);
    int cmp;

    it = PyObject_GetIter(iterable);
    if (it == NULL)
        return NULL;
    iternext = *Py_TYPE(it)->tp_iternext;

    for (;;) {
        item = iternext(it);
        if (item == NULL)
            break;
        cmp = PyObject_IsTrue(item);
        Py_DECREF(item);
        if (cmp < 0) {
            Py_DECREF(it);
            return NULL;
        }
        if (cmp == 0) {
            Py_DECREF(it);
            Py_RETURN_FALSE;
        }
    }
    Py_DECREF(it);
    if (PyErr_Occurred()) {
        if (PyErr_ExceptionMatches(PyExc_StopIteration))
            PyErr_Clear();
        else
            return NULL;
    }
    Py_RETURN_TRUE;
}

19voto

Arthur Tacca Points 2979

Je sais que c'est vieux, mais je pensais que cela pourrait être utile de montrer à quoi ressemblent ces fonctions dans le code. Cela illustre vraiment la logique, mieux que du texte ou un tableau à mon avis. En réalité, elles sont implémentées en C plutôt qu'en pur Python, mais elles sont équivalentes.

def any(iterable):
    for item in iterable:
        if item:
            return True
    return False

def all(iterable):
    for item in iterable:
        if not item:
            return False
    return True

En particulier, vous pouvez voir que le résultat pour les itérables vides est simplement le résultat naturel, pas un cas spécial. Vous pouvez également voir le comportement de court-circuitage; ce serait en fait plus de travail s'il n'y avait pas de court-circuitage.

Quand Guido van Rossum (le créateur de Python) a d'abord proposé d'ajouter any() et all(), il les a expliqués en postant exactement les extraits de code ci-dessus.

11voto

roippi Points 14363

Le code en question dont vous parlez provient de ma réponse donnée ici. Il était destiné à résoudre le problème de comparaison de plusieurs tableaux de bits - c'est-à-dire des collections de 1 et 0.

any et all sont utiles lorsque vous pouvez compter sur la "vérité" des valeurs - c'est-à-dire leur valeur dans un contexte booléen. 1 est True et 0 est False, une commodité sur laquelle cette réponse s'est appuyée. 5 se trouve également être True, donc lorsque vous mélangez cela dans vos entrées possibles... eh bien. Ça ne fonctionne pas.

Vous pourriez plutôt faire quelque chose comme cela :

[len(set(x)) > 1 for x in zip(*d['Drd2'])]

Cela manque d'esthétisme par rapport à la réponse précédente (j'aimais vraiment l'aspect de any(x) and not all(x)), mais cela fait le travail.

10voto

Jobin Points 1789
>>> any([False, False, False])
False
>>> any([False, True, False])
True
>>> all([False, True, True])
False
>>> all([True, True, True])
True

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X