Como funcionam todas e quaisquer funções do Python?

225

Estou tentando entender como as funções internas any()e all()Python funcionam.

Estou tentando comparar as tuplas para que, se algum valor for diferente, ele retorne Truee, se forem todos iguais, retorne False. Como eles estão trabalhando neste caso para retornar [Falso, Falso, Falso]?

dé um 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]

Que eu saiba, isso deve gerar

# [False, True, False]

já que (1,1) são iguais, (5,6) são diferentes e (0,0) são iguais.

Por que está avaliando para Falso para todas as tuplas?

O.rka
fonte
4
any (iterável): retorna true no primeiro encontro do objeto Truthy; caso contrário, retorna false. tudo (iterável): retorna o flase no primeiro encontro do objeto falso, caso contrário, retorna verdadeiro.
shadow0359

Respostas:

375

Você pode pensar aproximadamente anye allcomo uma série de operadores lógicos ore and, respectivamente.

qualquer

anyretornará Truequando pelo menos um dos elementos for Truthy. Leia sobre o Teste do valor da verdade.

tudo

allretornará Trueapenas quando todos os elementos forem Truthy.

Tabela da verdade

+-----------------------------------------+---------+---------+
|                                         |   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   |
+-----------------------------------------+---------+---------+

Nota 1: O caso iterável vazio é explicado na documentação oficial, como esta

any

Retorne Truese qualquer elemento do iterável for verdadeiro. Se o iterável estiver vazio, retorneFalse

Como nenhum dos elementos é verdadeiro, ele retorna Falseneste caso.

all

Retorne Truese todos os elementos do iterável forem verdadeiros ( ou se o iterável estiver vazio ).

Como nenhum dos elementos é falso, ele retorna Trueneste caso.


Nota 2:

Outra coisa importante a saber anye allé que ela irá causar um curto-circuito na execução, no momento em que souberem o resultado. A vantagem é que todo iterável não precisa ser consumido. Por exemplo,

>>> multiples_of_6 = (not (i % 6) for i in range(1, 10))
>>> any(multiples_of_6)
True
>>> list(multiples_of_6)
[False, False, False]

Aqui (not (i % 6) for i in range(1, 10))está uma expressão geradora que retorna Truese o número atual entre 1 e 9 for um múltiplo de 6. anyitera o multiples_of_6e, quando ele se encontra 6, encontra um valor Truthy, então retorna imediatamente Truee o restante multiples_of_6não é iterado. Isso é o que vemos quando imprimir list(multiples_of_6), o resultado de 7, 8e 9.

Essa coisa excelente é usada de maneira muito inteligente nesta resposta .


Com este entendimento básico, se olharmos para o seu código, você faz

any(x) and not all(x)

o que garante que, pelo menos um dos valores seja Truthy, mas não todos. É por isso que está voltando [False, False, False]. Se você realmente quis verificar se os dois números não são iguais,

print [x[0] != x[1] for x in zip(*d['Drd2'])]
thefourtheye
fonte
@ qualquer pessoa: se eu precisar usar tudo, exceto o caso em que ele retorne True para a lista vazia não é aceitável, o que fazemos? Eu não entendo a lógica por trás dando Verdadeiro se a lista está vazia ... o que significa que tudo ([]) == true
JavaSa
1
@JavaSa Você pode verificar explicitamente se a lista está vazia. Eu acredito que algo como bool(data) and all(...)deve funcionar.
thefourtheye
43

Como funcionam as funções anye o Python all?

anye allpegue iterables e retorne Truese houver algum ou todos (respectivamente) dos elementos 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

Se os iterables estiverem vazios, anyretornará Falsee allretornará True.

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

Eu estava demonstrando alle anypara os alunos nas aulas hoje. Eles estavam principalmente confusos sobre os valores de retorno para iterables vazios. Explicá-lo dessa maneira fez com que muitas lâmpadas acendessem.

Comportamento de atalho

Eles, anye all, tanto olhar para uma condição que lhes permite parar de avaliar. Os primeiros exemplos que eu dei exigiram que eles avaliassem o booleano de cada elemento da lista inteira.

(Observe que o literal da lista não é avaliado preguiçosamente - você pode obtê-lo com um iterador - mas isso é apenas para fins ilustrativos.)

Aqui está uma implementação Python de todo e qualquer:

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!

Obviamente, as implementações reais são escritas em C e têm muito mais desempenho, mas você pode substituir as opções acima e obter os mesmos resultados para o código nesta (ou em qualquer outra) resposta.

all

allverifica a existência de elementos False(para que ele possa retornar False) e, em seguida, retorna Truese nenhum deles foi 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

A maneira como anyfunciona é que ele verifica se há elementos True(para que possa retornar True), then it returnsFalseif 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!

Penso que, se você se lembrar do comportamento de atalho, entenderá intuitivamente como eles funcionam sem precisar fazer referência a uma Tabela da Verdade.

Evidência de all e anyatalho:

Primeiro, crie um noisy_iterator:

def noisy_iterator(iterable):
    for i in iterable:
        print('yielding ' + repr(i))
        yield i

e agora vamos iterar ruidosamente nas listas, usando nossos exemplos:

>>> 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

Nós podemos ver all paradas na primeira verificação booleana falsa.

E anypara na primeira verificação booleana 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

A fonte

Vamos olhar a fonte para confirmar o acima.

Aqui está a fonte paraany :

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;
}

E aqui está a fonte paraall :

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;
}
Aaron Hall
fonte
1
Nota: isso é consistente com os predicados matemáticos: "para todos" e "ele existe". A confusão pode ser que "para todos" e "para qualquer" são sinônimos em outros contextos ... en.wikipedia.org/wiki/List_of_logic_symbols
mcoolive
1
@ thanos.a está em Python/bltinmodule.c- eu adicionei ao acima.
Aaron Hall
14

Eu sei que isso é antigo, mas achei que seria útil mostrar como essas funções se parecem no código. Isso realmente ilustra a lógica, melhor que o texto ou uma tabela IMO. Na realidade, eles são implementados em C, e não em Python puro, mas são equivalentes.

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

Em particular, você pode ver que o resultado para iterables vazios é apenas o resultado natural, não um caso especial. Você também pode ver o comportamento em curto-circuito; seria realmente mais trabalho para não haver curto-circuito.

Quando Guido van Rossum (o criador do Python) propôs a adição any()eall() ele os explicou postando exatamente os trechos de código acima.

Arthur Tacca
fonte
10

O código em questão que você está perguntando vem da minha resposta dada aqui . O objetivo era resolver o problema de comparar várias matrizes de bits - ou seja, coleções de1 e 0.

anye allsão úteis quando você pode confiar na "veracidade" dos valores - ou seja, seu valor em um contexto booleano. 1 é Truee 0 é False, uma conveniência que essa resposta alavancou. 5 passa a ser tambémTrue , então quando você mistura isso em suas possíveis entradas ... bem. Não funciona

Você poderia fazer algo assim:

[len(set(x)) > 1 for x in zip(*d['Drd2'])]

Falta a estética da resposta anterior (eu realmente gostei da aparência any(x) and not all(x)), mas faz o trabalho.

Roippi
fonte
A influência de Colbert está atingindo CS / CE: en.wikipedia.org/wiki/Truthiness ? Estamos falando de lógica confusa? : D
Geof Sawaya
Como o OP pediu Truequando os valores são diferentes, o comprimento do conjunto deve ser 2, e não 1.
wombatonfire
@wombatonfire haha ​​boa captura. Eu ajustei minha resposta de 7 anos :)
roippi
Boas respostas não envelhecem :) Boa abordagem com um conjunto.
wombatonfire
7
>>> any([False, False, False])
False
>>> any([False, True, False])
True
>>> all([False, True, True])
False
>>> all([True, True, True])
True
Jobin
fonte
4
s = "eFdss"
s = list(s)
all(i.islower() for i in s )   # FALSE
any(i.islower() for i in s )   # TRUE
David Gladson
fonte
1

O conceito é simples:

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 
DK250
fonte
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 .
Ajmal Aamir
fonte