Как работают все без исключения функции Python?
Я пытаюсь понять, как работают any()
и all()
встроенные функции Python.
Я пытаюсь сравнить кортежи так, чтобы, если какое-либо значение отличается, оно возвращалось True
и если они все одинаковые, оно возвращалось False
. Как они работают в этом случае, чтобы возвращать [False, False, False]?
d
является defaultdict(list)
.
print d['Drd2']
# [[1, 5, 0], [1, 6, 0]]
print list(zip(*d['Drd2']))
# [(1, 1), (5, 6), (0, 0)]
print [any(x) and not all(x) for x in zip(*d['Drd2'])]
# [False, False, False]
Насколько мне известно, это должно выводить
# [False, True, False]
поскольку (1,1) одинаковы, (5,6) различны и (0,0) одинаковы.
Почему он принимает значение False для всех кортежей?
Смотрите Pythonic способ проверки выполнения условия для любого элемента списка для практического использования any
.
Переведено автоматически
Ответ 1
Вы можете грубо представить себе any
и all
как последовательность логических or
и and
операторов, соответственно.
Любой
any
вернется, True
когда хотя бы один из элементов соответствует действительности. Прочитайте о тестировании значений на истинность.
ВСЕ
all
вернет True
только тогда, когда все элементы соответствуют действительности.
Таблица истинности
+-----------------------------------------+---------+---------+
| | any | all |
+-----------------------------------------+---------+---------+
| All Truthy values | True | True |
+-----------------------------------------+---------+---------+
| All Falsy values | False | False |
+-----------------------------------------+---------+---------+
| One Truthy value (all others are Falsy) | True | False |
+-----------------------------------------+---------+---------+
| One Falsy value (all others are Truthy) | True | False |
+-----------------------------------------+---------+---------+
| Empty Iterable | False | True |
+-----------------------------------------+---------+---------+
Примечание 1: Пустой итерируемый регистр объясняется в официальной документации следующим образом
Верните,
True
если какой-либо элемент итерации имеет значение true. Если итерация пуста, вернитеFalse
Поскольку ни один из элементов не является true, он возвращает False
в этом случае.
Возвращает,
True
если все элементы iterable имеют значение true (или если iterable пуста).
Поскольку ни один из элементов не является false , он возвращает True
в этом случае.
Примечание 2:
Еще одна важная вещь, о которой нужно знать any
и all
, заключается в том, что выполнение будет прервано в тот момент, когда они узнают результат. Преимущество в том, что не нужно использовать всю итерацию целиком. Например,
>>> multiples_of_6 = (not (i % 6) for i in range(1, 10))
>>> any(multiples_of_6)
True
>>> list(multiples_of_6)
[False, False, False]
Здесь, (not (i % 6) for i in range(1, 10))
это выражение генератора, которое возвращает, True
если текущее число в пределах 1 и 9 кратно 6. any
выполняет итерацию multiples_of_6
и когда оно встречается 6
, оно находит истинное значение, поэтому оно немедленно возвращается True
, а остальная часть multiples_of_6
не повторяется. Это то, что мы видим, когда печатаем list(multiples_of_6)
результат 7
, 8
и 9
.
Эта превосходная вещь очень умно использована в этом ответе.
С этим базовым пониманием, если мы посмотрим на ваш код, вы сделаете
any(x) and not all(x)
который гарантирует, что по крайней мере одно из значений соответствует действительности, но не все из них. Вот почему он возвращается [False, False, False]
. Если вы действительно хотели проверить, не совпадают ли оба числа.,
print [x[0] != x[1] for x in zip(*d['Drd2'])]
Ответ 2
Как работают функции 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
, оба ищут условие, которое позволяет им прекратить вычисление. Первые примеры, которые я привел, требовали, чтобы они вычисляли логическое значение для каждого элемента во всем списке.
(Обратите внимание, что list literal сам по себе не вычисляется лениво - вы могли бы получить это с помощью итератора, но это только для иллюстрации.)
Вот реализация Any and 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 returns
Falseif 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!
Я думаю, если вы будете иметь в виду упрощенное поведение, вы интуитивно поймете, как они работают, без необходимости ссылаться на таблицу истинности.
Доказательства 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.
And any
stops on the first True boolean check:
>>> 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
The source
Let's look at the source to confirm the above.
Here's the 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;
}
And here's the 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;
}
Ответ 3
Я знаю, что это устарело, но я подумал, что было бы полезно показать, как эти функции выглядят в коде. Это действительно иллюстрирует логику, лучше, чем текст или таблица IMO. На самом деле они реализованы на C, а не на чистом Python, но они эквивалентны.
def any(iterable):
for item in iterable:
if item:
return True
return False
def all(iterable):
for item in iterable:
if not item:
return False
return True
В частности, вы можете видеть, что результат для пустых итераций - это просто естественный результат, а не частный случай. Вы также можете увидеть поведение короткого замыкания; на самом деле было бы больше работы, если бы короткого замыкания не было.
Когда Гвидо ван Россум (создатель Python) впервые предложил добавить any()
и all()
, он объяснил их, просто опубликовав в точности приведенные выше фрагменты кода.
Ответ 4
Код, о котором вы спрашиваете, взят из моего ответа, приведенного здесь. Это было предназначено для решения проблемы сравнения многобитовых массивов, то есть коллекций 1
и 0
.
any
и all
полезны, когда вы можете положиться на "истинность" значений, то есть на их значение в логическом контексте. 1 - это True
и 0 - это False
удобство, которое использовал этот ответ. 5 также может быть True
, поэтому, когда вы добавляете это в свои возможные входные данные... хорошо. Не работает.
Вы могли бы вместо этого сделать что-то вроде этого:
[len(set(x)) > 1 for x in zip(*d['Drd2'])]
Ему не хватает эстетики предыдущего ответа (мне действительно понравился внешний вид any(x) and not all(x)
), но он выполняет свою работу.