Làm thế nào để Python any
và các all
chức năng hoạt động?
any
và all
lấy iterables và trả về True
nếu có và tất cả (tương ứng) các phần tử 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
Nếu các lần lặp trống, any
trả về False
và all
trả về True
.
>>> any([]), all([])
(False, True)
Tôi đã chứng minh all
và any
cho các sinh viên trong lớp ngày hôm nay. Họ chủ yếu nhầm lẫn về các giá trị trả về cho các lần lặp trống. Giải thích theo cách này khiến rất nhiều bóng đèn bật lên.
Hành vi cắt ngắn
Họ, any
và all
, cả hai đều tìm kiếm một điều kiện cho phép họ ngừng đánh giá. Các ví dụ đầu tiên tôi đưa ra yêu cầu họ đánh giá boolean cho từng phần tử trong toàn bộ danh sách.
(Lưu ý rằng danh sách theo nghĩa đen không được đánh giá một cách lười biếng - bạn có thể nhận được điều đó với Iterator - nhưng đây chỉ là mục đích minh họa.)
Đây là một triển khai Python của bất kỳ và tất cả:
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!
Tất nhiên, các triển khai thực tế được viết bằng C và có hiệu suất cao hơn nhiều, nhưng bạn có thể thay thế ở trên và nhận được kết quả tương tự cho mã trong câu trả lời này (hoặc bất kỳ khác).
all
all
kiểm tra các phần tử được False
(để nó có thể trả về False
), sau đó nó trả về True
nếu không có phần tử nào trong số chúng 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
Cách thức any
hoạt động là nó kiểm tra các phần tử trở thành True
(để nó có thể trả về True), then it returns
Sai 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!
Tôi nghĩ rằng nếu bạn ghi nhớ hành vi cắt ngắn, bạn sẽ trực giác hiểu cách chúng hoạt động mà không cần phải tham khảo Bảng chân lý.
Bằng chứng all
và any
rút gọn:
Đầu tiên, tạo một nhiễu_iterator:
def noisy_iterator(iterable):
for i in iterable:
print('yielding ' + repr(i))
yield i
và bây giờ chúng ta hãy lặp đi lặp lại các danh sách một cách ồn ào, bằng cách sử dụng các ví dụ của chúng tô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
Chúng ta có thể thấy các all
điểm dừng trên kiểm tra boolean Sai đầu tiên.
Và any
dừng lại ở lần kiểm tra boolean True đầu tiên:
>>> 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
Nguồn
Hãy nhìn vào nguồn để xác nhận ở trên.
Đây là nguồn choany
:
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;
}
Và đây là nguồn choall
:
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;
}