Как работают Python anyи allфункции?
anyи allвзять итерируемые и вернуть, Trueесли любой и все (соответственно) из элементов 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
Если итерации пустые, anyвозвращается Falseи allвозвращается True.
>>> any([]), all([])
(False, True)
Я демонстрировал allи anyдля студентов сегодня в классе. Они были в основном озадачены возвращаемыми значениями для пустых итерируемых элементов. Такое объяснение вызвало включение множества лампочек.
Поведение быстрого доступа
Они, anyи all, как искать условия , что позволяет им прекратить оценивать. Первые примеры, которые я дал, требовали, чтобы они оценивали логическое значение для каждого элемента во всем списке.
(Обратите внимание, что литерал списка сам по себе не вычисляется лениво - вы можете получить это с помощью итератора - но это только для иллюстративных целей.)
Вот реализация Python любого и всех:
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!
Конечно, реальные реализации написаны на C и гораздо более производительны, но вы можете заменить вышеприведенное и получить те же результаты для кода в этом (или любом другом) ответе.
all
allпроверяет наличие элементов False(чтобы они могли вернуться False), а затем возвращает, Trueесли ни один из них не был 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
Способ anyработает так, что он проверяет наличие элементов True(поэтому он может возвращать 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!
Я думаю, что если вы будете помнить о кратковременном поведении, вы интуитивно поймете, как они работают, не обращаясь к таблице истинности.
Доказательства allи anyярлыки:
Сначала создайте noisy_iterator:
def noisy_iterator(iterable):
for i in iterable:
print('yielding ' + repr(i))
yield i
а теперь давайте с шумом перебираем списки, используя наши примеры:
>>> 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
Мы можем видеть allостановки на первой ложной проверке.
И anyостанавливается на первой истинной булевой проверке:
>>> 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
Источник
Давайте посмотрим на источник, чтобы подтвердить вышеизложенное.
Вот источник для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;
}
И вот источник для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;
}