Як працюють anyі allфункції Python ?
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;
}