Comment fonctionnent Python any
et ses all
fonctions?
any
et all
prendre des itérables et retourner True
si 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, any
renvoie False
et all
retourne True
.
>>> any([]), all([])
(False, True)
Je manifestais all
et any
pour 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, any
et 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
all
vérifie que les éléments doivent être False
(afin qu'il puisse revenir False
), puis il retourne True
si 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 any
fonctionne est qu'il vérifie que les éléments doivent être True
(afin qu'il puisse retourner True), then it returns
False if none of them were
True`.
>>> 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 all
et any
raccourci:
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 all
arrêts sur la première fausse vérification booléenne.
Et any
s'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;
}