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;
}