TL; DR
Começamos resumindo os dois comportamentos dos dois operadores lógicos and
e or
. Esses idiomas formarão a base de nossa discussão a seguir.
and
Retorne o primeiro valor Falsy se houver algum; caso contrário, retorne o último valor na expressão.
or
Retorne o primeiro valor verdadeiro, se houver algum; caso contrário, retorne o último valor na expressão.
O comportamento também está resumido nos documentos , especialmente nesta tabela:
O único operador que retorna um valor booleano, independentemente de seus operandos, é o not
operador.
Avaliações de "veracidade" e "verdadeiras"
A declaração
len(args) and max(args) - min(args)
É uma maneira concisa (e possivelmente menos legível) muito pythônica de dizer "se args
não estiver vazio, retorne o resultado de max(args) - min(args)
", caso contrário, retorne 0
. Em geral, é uma representação mais concisa de uma if-else
expressão. Por exemplo,
exp1 and exp2
Deve (aproximadamente) traduzir para:
r1 = exp1
if r1:
r1 = exp2
Ou equivalente,
r1 = exp1 if exp1 else exp2
Similarmente,
exp1 or exp2
É equivalente a,
r1 = exp1
if not r1:
r1 = exp2
Onde exp1
e exp2
são objetos Python arbitrários ou expressões que retornam algum objeto. A chave para entender os usos dos operadores lógicos and
e or
aqui é entender que eles não estão restritos a operar ou retornar valores booleanos. Qualquer objeto com um valor de veracidade pode ser testado aqui. Isto inclui int
, str
, list
, dict
, tuple
, set
, NoneType
, e objectos utilizador definido. As regras de curto-circuito também se aplicam.
Mas o que é verdade?
Refere-se a como os objetos são avaliados quando usados em expressões condicionais. @Patrick Haugh resume muito bem a verdade neste post .
Todos os valores são considerados "verdadeiros", exceto os seguintes, que são "falsos":
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
- um vazio list
{}
- um vazio dict
()
- um vazio tuple
''
- um vazio str
b''
- um vazio bytes
set()
- um vazio set
- um vazio
range
, comorange(0)
- objetos para os quais
obj.__bool__()
retorna False
obj.__len__()
retorna 0
Um valor "verdadeiro" irá satisfazer a verificação realizada por
instruções if
ou while
. Usamos "verdadeiro" e "falso" para diferenciar dos
bool
valores True
e False
.
Quão and
funciona
Nós construímos a pergunta do OP como uma segue para uma discussão sobre como esses operadores nesses casos.
Dada uma função com a definição
def foo(*args):
...
Como faço para retornar a diferença entre o valor mínimo e máximo em uma lista de zero ou mais argumentos?
Encontrar o mínimo e o máximo é fácil (use as funções integradas!). O único obstáculo aqui é lidar apropriadamente com o caso extremo em que a lista de argumentos pode estar vazia (por exemplo, chamar foo()
). Podemos fazer ambos em uma única linha, graças ao and
operador:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
Uma vez que and
é usada, a segunda expressão também deve ser avaliada se a primeira for True
. Observe que, se a primeira expressão for avaliada como verdadeira, o valor de retorno será sempre o resultado da segunda expressão . Se a primeira expressão for avaliada como Falsy, o resultado retornado será o resultado da primeira expressão.
Na função acima, If foo
recebe um ou mais argumentos, len(args)
é maior que 0
(um número positivo), então o resultado retornado é max(args) - min(args)
. OTOH, se nenhum argumento é passado, len(args)
é 0
que é Falsas e0
é devolvido.
Observe que uma maneira alternativa de escrever esta função seria:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
Ou, mais concisamente,
def foo(*args):
return 0 if not args else max(args) - min(args)
Claro, nenhuma dessas funções executa qualquer verificação de tipo, portanto, a menos que você confie completamente na entrada fornecida, não confie na simplicidade dessas construções.
Quão or
funciona
Eu explico o funcionamento de or
uma maneira semelhante com um exemplo inventado.
Dada uma função com a definição
def foo(*args):
...
Como você completaria foo
para retornar todos os números 9000
?
Usamos or
para lidar com o caso de canto aqui. Nós definimos foo
como:
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
# [9004]
foo(1, 2, 3, 4)
# 'No number over 9000!'
foo
executa uma filtragem na lista para reter todos os números 9000
. Se existir algum desses números, o resultado da compreensão da lista é uma lista não vazia que é verdadeira, então ela é retornada (curto-circuito em ação aqui). Se não existirem tais números, então o resultado da lista comp []
é Falsy. Portanto, a segunda expressão agora é avaliada (uma string não vazia) e é retornada.
Usando condicionais, poderíamos reescrever esta função como,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
Como antes, essa estrutura é mais flexível em termos de tratamento de erros.
and
(bem comoor
) não está restrito a trabalhar ou retornar valores booleanos.