Booleanos são um tipo de dado fundamental em Python, representando valores de verdade: True e False. Eles são essenciais para controle de fluxo, comparações e lógica condicional. Nesta aula, vamos explorar não apenas os valores booleanos explícitos, mas também como Python interpreta a veracidade de outros tipos de dados — os chamados valores falsy — e como os operadores lógicos funcionam, incluindo o importante conceito de curto-circuito.

Compreender booleanos e a avaliação de verdade é crucial para escrever código Python idiomático e eficiente. Muitas expressões que parecem não booleanas são avaliadas em contexto booleano, e saber quais valores são considerados falsos ajuda a evitar bugs e a escrever condições mais limpas.

True/False

Em Python, True e False são objetos do tipo bool, que é um subtipo do tipo inteiro (int). Na verdade, True é equivalente a 1 e False a 0, o que permite operações aritméticas (embora não seja recomendado por questões de legibilidade). Eles são gerados principalmente por operadores de comparação (como ==, !=, <, >, etc.) e usados em estruturas condicionais.

Exemplo de uso:

a = 10
b = 20
print(a == b)   # False
print(a < b)    # True

# Verificando o tipo
print(type(True))  # <class 'bool'>
print(isinstance(False, int))  # True

Note que os nomes True e False são palavras reservadas e devem ser escritos com a primeira letra maiúscula. Em Python, qualquer objeto pode ser usado em um contexto booleano (como em um if), e sua veracidade é determinada por regras específicas, que veremos a seguir.

Valores falsy

Em Python, valores considerados falsy (equivalentes a False) em um contexto booleano incluem: False, None, zero numérico (0, 0.0, 0j), sequências e coleções vazias ('', [], (), {}, set()), além de objetos que implementam o método __bool__ retornando False ou __len__ retornando zero. Todos os outros valores são considerados truthy.

Exemplos de valores falsy:

if 0:
    print('Não executa')
if '':
    print('Não executa')
if []:
    print('Não executa')
if None:
    print('Não executa')

# Truthy
if 1:
    print('Executa')
if 'texto':
    print('Executa')
if [1, 2]:
    print('Executa')

Conhecer os valores falsy permite escrever condições mais concisas. Por exemplo, em vez de if len(lista) == 0:, podemos usar if not lista:. Isso é considerado mais idiomático em Python.

Operadores lógicos

Python fornece três operadores lógicos: and, or e not. Eles operam sobre valores booleanos (ou valores que podem ser convertidos para booleanos) e retornam um valor booleano ou um dos operandos, dependendo do operador e do curto-circuito.

  • not: retorna o valor booleano inverso do operando. Se o operando for truthy, retorna False; se for falsy, retorna True.
  • and: retorna o primeiro operando se ele for falsy, caso contrário retorna o segundo operando.
  • or: retorna o primeiro operando se ele for truthy, caso contrário retorna o segundo operando.

Exemplos:

print(not True)        # False
print(not 0)           # True
print(True and False)  # False
print(True and 10)     # 10
print(False or 'texto') # 'texto'
print(0 or 42)         # 42

Note que and e or não necessariamente retornam True ou False; eles retornam um dos operandos. Isso é útil para atribuições condicionais, como em nome = usuario or 'Convidado'.

Curto-circuito

O curto-circuito é um comportamento dos operadores and e or que interrompe a avaliação assim que o resultado é determinado. No caso do and, se o primeiro operando for falsy, o segundo não é avaliado, pois o resultado já é falso. No or, se o primeiro for truthy, o segundo é ignorado.

Isso é importante para evitar erros e otimizar código. Por exemplo, ao verificar se um índice é válido em uma lista, podemos usar:

lista = [1, 2, 3]
indice = 5
if indice < len(lista) and lista[indice] == 3:
    print('Encontrou')
else:
    print('Não encontrou')
# O curto-circuito impede o acesso ao índice inválido

Outro exemplo comum é usar or para fornecer um valor padrão:

nome = input('Digite seu nome: ') or 'Anônimo'
print('Olá,', nome)

Se o usuário digitar uma string vazia (falsy), a expressão retorna 'Anônimo'.

Boas práticas

Ao usar operadores lógicos, prefira expressões claras e evite complexidade desnecessária. Use parênteses para agrupar condições quando misturar and e or. Lembre-se de que not tem precedência maior que and e or. Além disso, evite comparações redundantes como if x == True; simplesmente use if x:. Para verificar se um valor é exatamente True ou False, use is (ex.: if x is True:).

Referências

Exercícios

  1. Qual é a saída do código abaixo? Explique.

    print(not [] and 0 or 'fim')

    ✓ Resposta: A saída é 'fim'. A expressão é avaliada da esquerda para a direita: not [] é True (pois [] é falsy), então True and 0 retorna 0 (pois True é truthy, então retorna o segundo operando). Depois 0 or 'fim': como 0 é falsy, retorna 'fim'.
  2. Escreva uma expressão que atribua à variável saudacao o valor 'Bem-vindo' se a variável usuario for truthy, caso contrário 'Convidado'. Use o operador or.

    ✓ Resposta: saudacao = usuario or 'Convidado' (mas note que se usuario for uma string vazia, será 'Convidado'; se for qualquer string não vazia, será o próprio valor de usuario. Para obter exatamente 'Bem-vindo', seria necessário usar um if/else, mas o exercício pede o operador or.)
  3. O código abaixo tem um bug potencial devido a curto-circuito? Explique.

    def get_valor():
        print('get_valor foi chamada')
        return 10
    
    if False and get_valor():
        print('condição verdadeira')
    

    ✓ Resposta: Não há bug; o curto-circuito impede que get_valor() seja chamada, pois o primeiro operando é False, então o and já sabe que o resultado será False. Isso é intencional e evita chamadas desnecessárias.
  4. Dada a lista valores = [0, 1, '', 'texto', [], [1]], use uma compreensão de lista para criar uma nova lista contendo apenas os valores truthy.

    ✓ Resposta: [x for x in valores if x] resulta em [1, 'texto', [1]].
  5. Escreva uma função verificar_acesso(usuario, senha) que retorne True se o usuário for 'admin' e a senha for '1234', ou se o usuário for 'user' e a senha for 'abcd'. Use operadores lógicos e curto-circuito. (Dica: use or entre duas condições and).

    ✓ Resposta:
    def verificar_acesso(usuario, senha):
        return (usuario == 'admin' and senha == '1234') or (usuario == 'user' and senha == 'abcd')