Як працюють всі функції Python?


225

Я намагаюся зрозуміти , як 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) однакові.

Чому для всіх кортежів це оцінюється "Неправдиво"?


4
будь-який (ітерабельний): повертає true при першому зустрічі об'єкта Truthy, інше повертає false. all (ітерабельний): повертає flase при першому зіткненні з ложним об'єктом, інше повертає true.
тінь0359

Відповіді:


375

Ви можете орієнтовно мислити anyі allяк ряд логічних orі andоператорів відповідно.

будь-який

anyповернеться, Trueколи хоча б одним із елементів буде Truthy. Читайте про тестування цінності на істину.

всі

allповернеться Trueлише тоді, коли всі елементи будуть Truthy.

Таблиця правди

+-----------------------------------------+---------+---------+
|                                         |   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: Пустий ітерабельний випадок пояснюється в офіційній документації, як це

any

Повертайтеся, Trueякщо будь-який елемент ітерабельного істинний. Якщо ітерабел порожній, повернітьсяFalse

Оскільки жоден з елементів не відповідає дійсності, він повертається Falseв цьому випадку.

all

Повертайтеся, Trueякщо всі елементи ітерабельного файлу є істинними ( або якщо ітерабел порожній ).

Оскільки жоден із елементів не є хибним, він повертається 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, воно знаходить значення Truthy, тому воно негайно повертається True, а решта multiples_of_6не повторюється. Це те , що ми бачимо , коли ми виводимо list(multiples_of_6), результат 7, 8і 9.

Ця відмінна річ дуже спритно використовується у цій відповіді .


З цим основним розумінням, якщо ми подивимось на ваш код, ви це зробите

any(x) and not all(x)

що гарантує, що, принаймні, одним із значень є Truthy, але не всі вони. Ось чому воно повертається [False, False, False]. Якщо ви дійсно хотіли перевірити, чи не обидва числа однакові,

print [x[0] != x[1] for x in zip(*d['Drd2'])]

@anyone: якщо мені потрібно використовувати всі, крім випадків, коли це повертає True для порожнього списку, не прийнятно, що ми робимо? Я не розумію логіку надання True, якщо список порожній ... тобто все ([]) == Істинно
JavaSa

1
@JavaSa Ви можете явно перевірити, чи список порожній. Я вважаю, що щось подібне bool(data) and all(...)повинно працювати.
thefourtheye

43

Як працюють 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;
}

1
Примітка: це відповідає математичним предикатам: "для всіх" і "воно існує". Плутанина може полягати в тому, що "ЗА ВСІХ" і "ЗА ВСЕ" є синонімами в інших контекстах ... en.wikipedia.org/wiki/List_of_logic_symbols
mcoolive

1
@ thanos.a це Python/bltinmodule.c- я додав його до вищезазначеного.
Аарон Холл

14

Я знаю, що це давнє, але я подумав, що може бути корисно показати, як виглядають ці функції у коді. Це дійсно ілюструє логіку, кращу, ніж текст або таблиця ІМО. Насправді вони реалізовані на 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() , він пояснив їх, просто розмістивши саме вказані вище фрагменти коду.


10

Код, про який ви питаєте, походить від моєї відповіді, наведеної тут . Він мав на меті вирішити проблему порівняння декількох бітових масивів - тобто колекцій 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)), але це робить роботу.


Вплив Колберта досягає CS / CE: en.wikipedia.org/wiki/ Правда ? Ми говоримо про нечітку логіку? : D
Geof Sawaya

Як ОП просили , Trueколи значення різні, довжина набору повинна бути 2, а НЕ 1.
wombatonfire

@wombatonfire ха-ха гарний улов. Я підкоригував свою 7-річну відповідь :)
roippi

Гарні відповіді не старіють :) Хороший підхід із набором.
вогнепальний вогонь

7
>>> any([False, False, False])
False
>>> any([False, True, False])
True
>>> all([False, True, True])
False
>>> all([True, True, True])
True


1

Концепція проста:

M =[(1, 1), (5, 6), (0, 0)]

1) print([any(x) for x in M])
[True, True, False] #only the last tuple does not have any true element

2) print([all(x) for x in M])
[True, True, False] #all elements of the last tuple are not true

3) print([not all(x) for x in M])
[False, False, True] #NOT operator applied to 2)

4) print([any(x)  and not all(x) for x in M])
[False, False, False] #AND operator applied to 1) and 3)
# if we had M =[(1, 1), (5, 6), (1, 0)], we could get [False, False, True]  in 4)
# because the last tuple satisfies both conditions: any of its elements is TRUE 
#and not all elements are TRUE 

0
list = [1,1,1,0]
print(any(list)) # will return True because there is  1 or True exists
print(all(list)) # will return False because there is a 0 or False exists
return all(a % i for i in range(3, int(a ** 0.5) + 1)) # when number is divisible it will return False else return True but the whole statement is False .
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.