¿Cómo funcionan las funciones anyy de Python all?
anyy alltomar iterables y devolver Truesi alguno y todos (respectivamente) de los elementos son 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 los iterables están vacíos, anydevuelve Falsey alldevuelve True.
>>> any([]), all([])
(False, True)
Me estaba manifestando ally anypara estudiantes en clase hoy. En su mayoría estaban confundidos acerca de los valores de retorno para iterables vacíos. Explicarlo de esta manera provocó que se encendieran muchas bombillas.
Comportamiento de atajos
Ellos anyy allambos buscan una condición que les permita dejar de evaluar. Los primeros ejemplos que les di requieren que evalúen el valor booleano para cada elemento en toda la lista.
(Tenga en cuenta que la lista literal no se evalúa perezosamente en sí misma ; podría obtener eso con un iterador , pero esto es solo para fines ilustrativos).
Aquí hay una implementación de Python de todos y cada uno:
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!
Por supuesto, las implementaciones reales están escritas en C y son mucho más eficaces, pero puede sustituir lo anterior y obtener los mismos resultados para el código en esta (o en cualquier otra) respuesta.
all
allcomprueba si hay elementos False(para que pueda regresar False), luego regresa Truesi ninguno de ellos lo fue 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 forma en que anyfunciona es que comprueba si hay elementos True(para que pueda devolver 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!
Creo que si tiene en cuenta el comportamiento abreviado, comprenderá intuitivamente cómo funcionan sin tener que hacer referencia a una Tabla de Verdad.
Evidencia de allyany atajo:
Primero, crea un noisy_iterator:
def noisy_iterator(iterable):
for i in iterable:
print('yielding ' + repr(i))
yield i
y ahora solo recorramos las listas ruidosamente, usando nuestros ejemplos:
>>> 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
Podemos ver allparadas en el primer cheque falso booleano.
Y se anydetiene en la primera verificación booleana verdadera:
>>> 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 fuente
Miremos la fuente para confirmar lo anterior.
Aquí está la fuente 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;
}
Y aquí está la fuente 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;
}