Comment fonctionnent toutes les fonctions de Python?

225

J'essaie de comprendre comment les fonctions intégrées any()et all()Python fonctionnent.

J'essaie de comparer les tuples de sorte que si une valeur est différente, elle reviendra Trueet si elles sont toutes identiques, elle reviendra False. Comment travaillent-ils dans ce cas pour revenir [Faux, Faux, Faux]?

dest 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, cela devrait produire

# [False, True, False]

puisque (1,1) sont identiques, (5,6) sont différents et (0,0) sont identiques.

Pourquoi est-il évalué à False pour tous les tuples?

O.rka
la source
4
any (itérable): renvoie true lors de la première rencontre avec un objet Truthy sinon renvoie false. all (itérable): retourne flase lors de la première rencontre avec un objet faux sinon retourne vrai.
shadow0359

Réponses:

375

Vous pouvez approximativement penser à anyet allcomme une série d' opérateurs logiques oret and, respectivement.

tout

anyreviendra Truequand au moins un des éléments est Truthy. Lisez à propos de Truth Value Testing.

tout

allne reviendra Trueque lorsque tous les éléments seront vrais.

Table de vérité

+-----------------------------------------+---------+---------+
|                                         |   any   |   all   |
+-----------------------------------------+---------+---------+
| All Truthy values                       |  True   |  True   |
+-----------------------------------------+---------+---------+
| All Falsy values                        |  False  |  False  |
+-----------------------------------------+---------+---------+
| One Truthy value (all others are Falsy) |  True   |  False  |
+-----------------------------------------+---------+---------+
| One Falsy value (all others are Truthy) |  True   |  False  |
+-----------------------------------------+---------+---------+
| Empty Iterable                          |  False  |  True   |
+-----------------------------------------+---------+---------+

Remarque 1: le cas itérable vide est expliqué dans la documentation officielle, comme ceci

any

Retourne Truesi un élément de l'itérable est vrai. Si l'itérable est vide, retournezFalse

Puisqu'aucun des éléments n'est vrai, il revient Falsedans ce cas.

all

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

Puisqu'aucun des éléments n'est faux, il revient Truedans ce cas.


Note 2:

Une autre chose importante à savoir anyet allc'est qu'elle court-circuitera l'exécution, au moment où ils connaîtront le résultat. L'avantage est qu'il n'est pas nécessaire de consommer l'intégralité de l'itére. Par exemple,

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

Ici, (not (i % 6) for i in range(1, 10))est une expression de générateur qui retourne Truesi le nombre actuel entre 1 et 9 est un multiple de 6. anyitère le multiples_of_6et quand il se rencontre 6, il trouve une valeur Truthy, donc il revient immédiatement True, et le reste du multiples_of_6n'est pas itéré. Voilà ce que nous voyons quand nous imprimons list(multiples_of_6), le résultat de 7, 8et 9.

Cette excellente chose est utilisée très intelligemment dans cette réponse .


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

any(x) and not all(x)

ce qui garantit qu'au moins une des valeurs est Truthy mais pas toutes. C'est pourquoi il revient [False, False, False]. 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'])]
thefourtheye
la source
@anyone: si j'ai besoin de tout utiliser, mais le cas dans lequel il renvoie True pour une liste vide n'est pas acceptable, que faisons-nous? Je ne comprends pas la logique derrière donner True si la liste est vide ... ce qui signifie tout ([]) == True
JavaSa
1
@JavaSa Vous pouvez vérifier explicitement si la liste est vide. Je crois que quelque chose comme ça bool(data) and all(...)devrait marcher.
thefourtheye
43

Comment fonctionnent Python anyet ses allfonctions?

anyet allprendre des itérables et retourner Truesi l'un et tous (respectivement) des éléments le sont True.

>>> any([0, 0.0, False, (), '0']), all([1, 0.0001, True, (False,)])
(True, True)            #   ^^^-- truthy non-empty string
>>> any([0, 0.0, False, (), '']), all([1, 0.0001, True, (False,), {}])
(False, False)                                                #   ^^-- falsey

Si les itérables sont vides, anyrenvoie Falseet allretourne True.

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

Je manifestais allet anypour les étudiants en classe aujourd'hui. Ils étaient surtout confus au sujet des valeurs de retour pour les itérables vides. En l'expliquant de cette façon, de nombreuses ampoules se sont allumées.

Comportement de raccourci

Ils, anyet all, à la fois regard d'une condition qui leur permet d'arrêter l' évaluation. Les premiers exemples que j'ai donnés les ont obligés à évaluer le booléen pour chaque élément de la liste entière.

(Notez que le littéral de liste n'est pas lui-même évalué paresseusement - vous pouvez l'obtenir avec un itérateur - mais cela est juste à des fins d'illustration.)

Voici une implémentation Python de tout et de tout:

def any(iterable):
    for i in iterable:
        if i:
            return True
    return False # for an empty iterable, any returns False!

def all(iterable):
    for i in iterable:
        if not i:
            return False
    return True  # for an empty iterable, all returns True!

Bien sûr, les implémentations réelles sont écrites en C et sont beaucoup plus performantes, mais vous pouvez remplacer ce qui précède et obtenir les mêmes résultats pour le code dans cette réponse (ou toute autre).

all

allvérifie que les éléments doivent être False(afin qu'il puisse revenir False), puis il retourne Truesi aucun d'entre eux ne l'était False.

>>> all([1, 2, 3, 4])                 # has to test to the end!
True
>>> all([0, 1, 2, 3, 4])              # 0 is False in a boolean context!
False  # ^--stops here!
>>> all([])
True   # gets to end, so True!

any

La façon dont cela anyfonctionne est qu'il vérifie que les éléments doivent être True(afin qu'il puisse retourner True), then it returnsFalse if none of them wereTrue`.

>>> any([0, 0.0, '', (), [], {}])     # has to test to the end!
False
>>> any([1, 0, 0.0, '', (), [], {}])  # 1 is True in a boolean context!
True   # ^--stops here!
>>> any([])
False   # gets to end, so False!

Je pense que si vous gardez à l'esprit le comportement de raccourci, vous comprendrez intuitivement comment ils fonctionnent sans avoir à référencer une table de vérité.

Preuve allet anyraccourci:

Créez d'abord un noisy_iterator:

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

et maintenant, parcourons les listes bruyamment, en utilisant nos exemples:

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

Nous pouvons voir des allarrêts sur la première fausse vérification booléenne.

Et anys'arrête sur la première vérification booléenne True:

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

La source

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

Voici la source deany :

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 deall :

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;
}
Aaron Hall
la source
1
Remarque: ceci est cohérent avec les prédicats mathématiques: "pour tous" et "il existe". La confusion peut être que "POUR TOUS" et "POUR TOUT" sont des synonymes dans d'autres contextes ... en.wikipedia.org/wiki/List_of_logic_symbols
mcoolive
1
@ thanos.a c'est dans Python/bltinmodule.c- je l'ai ajouté à ce qui précède.
Aaron Hall
14

Je sais que c'est vieux, mais j'ai pensé qu'il pourrait être utile de montrer à quoi ressemblent ces fonctions dans le code. Cela illustre vraiment la logique, mieux que du texte ou un tableau IMO. En réalité, ils sont implémentés en C plutôt qu'en Python pur, mais ceux-ci sont équivalents.

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 juste le résultat naturel, pas un cas spécial. Vous pouvez également voir le comportement de court-circuit; ce serait en fait plus de travail pour qu'il n'y ait pas de court-circuit.

Lorsque Guido van Rossum (le créateur de Python) a proposé pour la première fois d'ajouter any()etall() , il les a expliqués en affichant exactement les extraits de code ci-dessus.

Arthur Tacca
la source
10

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

anyet allsont utiles lorsque vous pouvez compter sur la «véracité» des valeurs - c'est-à-dire leur valeur dans un contexte booléen. 1 est Trueet 0 est False, une commodité dont cette réponse a tiré parti. 5 se trouve être aussi True, donc quand vous mélangez cela dans vos entrées possibles ... eh bien. Ça ne marche pas.

Vous pouvez plutôt faire quelque chose comme ceci:

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

Il manque l'esthétique de la réponse précédente (j'ai vraiment aimé le look de any(x) and not all(x)), mais il fait le travail.

roippi
la source
L' influence de Colbert atteint CS / CE: en.wikipedia.org/wiki/Truthiness ? Parlons-nous de logique floue? : D
Geof Sawaya
Comme l'OP a demandé Truequand les valeurs sont différentes, la longueur de l'ensemble devrait être de 2, pas de 1.
wombatonfire
@wombatonfire haha ​​bonne prise. J'ai ajusté ma réponse de 7 ans :)
roippi Il y a
Les bonnes réponses ne vieillissent pas :) Belle approche avec un ensemble.
wombatonfire Il y a
7
>>> any([False, False, False])
False
>>> any([False, True, False])
True
>>> all([False, True, True])
False
>>> all([True, True, True])
True
Jobin
la source
4
s = "eFdss"
s = list(s)
all(i.islower() for i in s )   # FALSE
any(i.islower() for i in s )   # TRUE
David Gladson
la source
1

Le concept est simple:

M =[(1, 1), (5, 6), (0, 0)]

1) print([any(x) for x in M])
[True, True, False] #only the last tuple does not have any true element

2) print([all(x) for x in M])
[True, True, False] #all elements of the last tuple are not true

3) print([not all(x) for x in M])
[False, False, True] #NOT operator applied to 2)

4) print([any(x)  and not all(x) for x in M])
[False, False, False] #AND operator applied to 1) and 3)
# if we had M =[(1, 1), (5, 6), (1, 0)], we could get [False, False, True]  in 4)
# because the last tuple satisfies both conditions: any of its elements is TRUE 
#and not all elements are TRUE 
DK250
la source
0
list = [1,1,1,0]
print(any(list)) # will return True because there is  1 or True exists
print(all(list)) # will return False because there is a 0 or False exists
return all(a % i for i in range(3, int(a ** 0.5) + 1)) # when number is divisible it will return False else return True but the whole statement is False .
Ajmal Aamir
la source