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 都在寻找允许他们停止评估的条件。我给出的第一个示例要求他们评估整个列表中每个元素的布尔值。
(请注意,列表文字 本身并不是 懒惰评估的 - 你可以使用 Iterator 得到它 - 但这仅用于说明目的。)
这是任何和所有的 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),然后如果它们都不是False,则返回True。
>>> 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 returnsFalseif 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 在第一次 False 布尔检查时停止。
而any 在第一次 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
来源
让我们看一下来源以确认上述内容。
这是source for 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;
}
这是source for 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;
}