Sua dose diária de programação

Conceito, 3 exemplos e 3 exercícios: uma pequena conquista de cada vez.

sábado, 17 de outubro de 2026
← Ontem Amanhã →
✦   Lição de hoje

Operadores aritméticos, de comparação e lógicos

Operadores são os símbolos que fazem contas e perguntas sobre valores. Os aritméticos são +, -, *, / (divisão que sempre dá float), // (divisão inteira), % (resto) e ** (potência). Quando aparecem juntos, seguem uma ordem de precedência: primeiro **, depois *, /, // e %, e por fim + e -. Parênteses mudam essa ordem e deixam a intenção clara.

Python Fundamentos Iniciante 3 exemplos + 3 exercícios
42 lições publicadas 10 linguagens novas lições todo dia útil
Python / Fundamentos

Operadores aritméticos, de comparação e lógicos

por Sutton Ashford
Iniciante

Entenda o conceito

Operadores são os símbolos que fazem contas e perguntas sobre valores. Os aritméticos são +, -, *, / (divisão que sempre dá float), // (divisão inteira), % (resto) e ** (potência). Quando aparecem juntos, seguem uma ordem de precedência: primeiro **, depois *, /, // e %, e por fim + e -. Parênteses mudam essa ordem e deixam a intenção clara.

Os operadores de comparação (==, !=, <, <=, >, >=) sempre devolvem True ou False. Eles comparam números (7 == 7.0 é verdadeiro) e textos, letra a letra. Dois cuidados: contas com float acumulam erro de arredondamento, então prefira math.isclose() à igualdade exata, e is pergunta se é o mesmo objeto, por isso é usado com None.

Os lógicos and, or e not combinam condições. Em Python, and e or param assim que o resultado está decidido (curto-circuito) e devolvem um dos próprios operandos, o que permite escrever valores padrão (apelido or nome) e guardas (qtd > 0 and total / qtd > 7).

↳ Pontos-chave
  • Precedência: ** primeiro, depois *, /, // e %, depois + e -; na dúvida, use parênteses.
  • -2 ** 2 dá -4, porque a potência vem antes do sinal; // e % arredondam para baixo, então -7 // 2 dá -4.
  • x += 1, x *= 2, x **= 2 e afins são atalhos para x = x op valor.
  • Comparações devolvem bool; não use == com contas de float (0.1 + 0.2 == 0.3 é False): prefira math.isclose(). Para None, use is.
  • Ordem dos lógicos: not, depois and, depois or; and e or param no primeiro operando que decide e devolvem esse operando.

Do conceito à prática

3 exemplos para ver a ideia funcionando.

01Ajustando uma receita com operadores aritméticos

porcoes.py
# porcoes.py: operadores aritméticos ao ajustar uma receita.

FARINHA_POR_PORCAO = 45  # gramas de farinha para uma porção
porcoes = 8

# + - * / funcionam como na matemática.
farinha = FARINHA_POR_PORCAO * porcoes
print("Farinha total:", farinha, "g")

# ** é a potência: área de uma forma redonda de 22 cm.
raio = 22 / 2
area = 3.14159 * raio ** 2  # ** vem antes do *
print(f"Área da forma: {area:.1f} cm²")

# Precedência: ** > * / // % > + -. Parênteses mudam a ordem.
print("2 + 3 * 4 =", 2 + 3 * 4)
print("(2 + 3) * 4 =", (2 + 3) * 4)
print("-2 ** 2 =", -2 ** 2)      # o ** vem antes do sinal de menos
print("(-2) ** 2 =", (-2) ** 2)

# // e % arredondam para baixo, inclusive com negativos.
print("7 // 2 =", 7 // 2, "| -7 // 2 =", -7 // 2)
print("7 % 3 =", 7 % 3, "| -7 % 3 =", -7 % 3)

# Operadores de atribuição composta: x op= y equivale a x = x op y.
ovos = 3
ovos *= 2   # dobra a receita
ovos -= 1   # um ovo quebrou
ovos **= 2  # só para mostrar: eleva ao quadrado
print("Ovos depois das contas:", ovos)

O exemplo usa todos os operadores aritméticos numa receita: multiplicação para a farinha de 8 porções, potência para a área da forma e as linhas de precedência mostram por que 2 + 3 * 4 dá 14 e -2 ** 2 dá -4. O ** é avaliado antes do sinal de menos e do *, por isso 3.14159 * raio ** 2 calcula a área sem parênteses.

Repare também nos negativos: // e % arredondam sempre para baixo, então -7 // 2 é -4 e -7 % 3 é 2. No fim, os operadores compostos (*=, -=, **=) atualizam a mesma variável sem repetir o nome dela.

02Comparando notas e nomes de alunos

notas.py
# notas.py: operadores de comparação com números e textos.
import math

nota_ana = 7.5
nota_bruno = 7.50

# Comparações devolvem bool; int e float com o mesmo valor são iguais.
print("Mesma nota?", nota_ana == nota_bruno)
print("7 == 7.0?", 7 == 7.0)
print("Texto e número: '7' == 7?", "7" == 7)
print("Bruno passou de 7?", nota_bruno > 7)
print("Ana diferente de 10?", nota_ana != 10)

# float tem erro de arredondamento: evite == com contas decimais.
media = (0.1 + 0.2) * 10
print("Média calculada:", media)
print("media == 3.0?", media == 3.0)
print("math.isclose(media, 3.0)?", math.isclose(media, 3.0))

# Textos são comparados letra a letra, pelo código de cada caractere.
print("'Ana' < 'Bruno'?", "Ana" < "Bruno")
print("'ana' < 'Bruno'?", "ana" < "Bruno")  # minúsculas vêm depois
print("Ignorando a caixa:", "ana".lower() < "bruno".lower())

# is pergunta se é o MESMO objeto; use-o com None.
recuperacao = None
print("Sem recuperação?", recuperacao is None)

Cada comparação gera um bool. Números de tipos diferentes com o mesmo valor são iguais (7 == 7.0), mas um texto nunca é igual a um número. O caso da média mostra a armadilha do float: (0.1 + 0.2) * 10 dá 3.0000000000000004, então == falha e math.isclose() acerta.

Textos são comparados caractere a caractere pelo código de cada um, e todas as maiúsculas vêm antes das minúsculas; por isso "ana" < "Bruno" é falso. Converter com lower() resolve. Por fim, is None é a forma idiomática de perguntar se uma variável ainda não tem valor.

03Cupons da loja com curto-circuito

cupom.py
# cupom.py: and, or e not devolvem um dos operandos (curto-circuito).

def preco_final(preco, cupom, itens):
    # or devolve o primeiro valor verdadeiro: "" vira "SEM-CUPOM".
    codigo = cupom or "SEM-CUPOM"

    # and para no primeiro falso: se itens for 0, a divisão nem acontece.
    preco_medio_alto = itens > 0 and preco / itens > 50

    # not tem precedência maior que and, que tem maior que or.
    ganha_brinde = not preco_medio_alto and itens >= 3 or codigo == "VIP"

    desconto = 0.1 if codigo != "SEM-CUPOM" else 0
    total = preco - preco * desconto
    return f"{codigo}: R$ {total:.2f} | brinde: {ganha_brinde}"


def main():
    # and e or devolvem um dos valores, não necessariamente True/False.
    print("0 or 15 ->", 0 or 15)
    print("'' or 'padrão' ->", "" or "padrão")
    print("3 and 'ok' ->", 3 and "ok")
    print("0 and 1 / 0 ->", 0 and 1 / 0)  # 1 / 0 nunca é avaliado
    print()
    print(preco_final(120.0, "", 3))
    print(preco_final(300.0, "PROMO", 2))
    print(preco_final(0.0, "VIP", 0))


if __name__ == "__main__":
    main()

As primeiras linhas mostram que or devolve o primeiro valor verdadeiro e and o primeiro falso (ou o último, se todos forem verdadeiros). Em 0 and 1 / 0, o Python para no 0 e a divisão por zero nunca acontece.

Em preco_final(), cupom or "SEM-CUPOM" cria um valor padrão, itens > 0 and preco / itens > 50 protege a divisão e a linha do brinde é lida como ((not preco_medio_alto) and itens >= 3) or codigo == "VIP", pela ordem de precedência dos lógicos. O cliente VIP ganha brinde mesmo com o carrinho vazio, porque basta um lado do or ser verdadeiro.


Agora é com você

Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.

01Forma maior para a receitaFácil

Uma receita de bolo leva 300 g de farinha e 4 ovos numa forma de 20 cm de diâmetro. Calcule as quantidades para uma forma de 26 cm, sabendo que a massa acompanha a área, e mostre o fator, a farinha e os ovos separados em parte inteira e fração.

↳ Requisitos
  • O fator é calculado com / e **, usando parênteses para dividir antes de elevar ao quadrado.
  • A parte inteira dos ovos é obtida com // e a fração com %.
  • A farinha extra é a diferença entre a quantidade nova e a original.
  • A saída tem exatamente 3 linhas, formatadas com f-strings.
código inicial
# forma.py: ajustar a receita para uma forma maior.
DIAMETRO_ORIGINAL = 20  # cm
diametro_novo = 26      # cm
farinha = 300           # gramas na receita original
ovos = 4

# calcule o fator e as novas quantidades
saída esperada
Fator de aumento: 1.69
Farinha: 507 g (207 g a mais)
Ovos: 6 inteiros e mais 0.76 de ovo
Ver dica

Pense no que acontece se o ** for aplicado só ao 20: a potência tem precedência maior que a divisão.

Ver resposta
# forma.py: ajustar a receita para uma forma maior.
DIAMETRO_ORIGINAL = 20  # cm
diametro_novo = 26      # cm
farinha = 300           # gramas na receita original
ovos = 4

# A área cresce com o quadrado do diâmetro: ** 2.
fator = (diametro_novo / DIAMETRO_ORIGINAL) ** 2
farinha_nova = farinha * fator
farinha_extra = farinha_nova - farinha
ovos_novos = ovos * fator

# // 1 tira a parte inteira e % 1 a parte fracionária.
ovos_inteiros = int(ovos_novos // 1)
fracao_ovo = ovos_novos % 1

print(f"Fator de aumento: {fator:.2f}")
print(f"Farinha: {farinha_nova:.0f} g ({farinha_extra:.0f} g a mais)")
print(f"Ovos: {ovos_inteiros} inteiros e mais {fracao_ovo:.2f} de ovo")

Passo a passo

  1. DIAMETRO_ORIGINAL fica em maiúsculas porque é um dado fixo da receita; o diâmetro novo, a farinha e os ovos são variáveis comuns.
  2. (diametro_novo / DIAMETRO_ORIGINAL) ** 2 divide primeiro, por causa dos parênteses, e só então eleva ao quadrado: 1.3 ** 2 dá 1.6900000000000002, que o :.2f mostra como 1.69.
  3. farinha * fator e ovos * fator multiplicam um int por um float, então os resultados são float (cerca de 507 e 6.76, com resíduos de arredondamento nas últimas casas).
  4. farinha_nova - farinha mostra quanto de farinha a mais será preciso comprar.
  5. ovos_novos // 1 dá o quociente inteiro da divisão por 1, ou seja, a parte inteira (6.0, ainda um float); o int() tira o .0 para exibir 6.
  6. ovos_novos % 1 dá o resto da divisão por 1, que é a parte fracionária (0.7600000000000007, exibida como 0.76 pelo :.2f).
  7. Nas f-strings, :.0f mostra a farinha sem casas decimais e :.2f mostra o fator e a fração com duas casas.

Por que funciona

A quantidade de massa acompanha a área da forma, e a área de um círculo é proporcional ao quadrado do diâmetro. Por isso o fator é a razão entre os diâmetros elevada a 2, escrita com **, e os parênteses garantem que a divisão aconteça antes da potência.

Os operadores // e % com divisor 1 separam um número em parte inteira e parte fracionária: o primeiro arredonda para baixo e o segundo devolve o que sobrou.

Erros comuns

  • fator = diametro_novo / DIAMETRO_ORIGINAL ** 2: o ** tem precedência maior que /, então só o 20 é elevado ao quadrado e o fator vira 0.065. Ponha a divisão entre parênteses.
  • fator = (diametro_novo / DIAMETRO_ORIGINAL) ^ 2: dá TypeError, porque ^ é o "ou exclusivo" bit a bit, não a potência. Em Python a potência é **.
  • fator = (diametro_novo / DIAMETRO_ORIGINAL) * 2: dobra em vez de elevar ao quadrado, e o fator vira 2.6. Use ** 2.
  • ovos_inteiros = round(ovos_novos): dá 7, porque round() arredonda para o mais próximo; o enunciado pede a parte inteira, que é 6. Use // 1 (ou int()).

Outra forma de resolver

A potência também existe como função: pow(diametro_novo / DIAMETRO_ORIGINAL, 2). O ** é mais comum em contas simples; já a parte inteira e a fração podem sair juntas com divmod(ovos_novos, 1), útil quando você precisa das duas ao mesmo tempo.

Saída esperada

Fator de aumento: 1.69
Farinha: 507 g (207 g a mais)
Ovos: 6 inteiros e mais 0.76 de ovo

02Conferência do caixa da papelariaMédio

Uma caneta de R$ 1.10 e uma borracha de R$ 2.20 foram pagas com R$ 3.30 e o cliente digitou o cupom "Volta10", cadastrado como "VOLTA10". Mostre o total calculado e compare pagamento e cupom de duas formas: a direta, que falha, e a correta.

↳ Requisitos
  • O pagamento é comparado com == e depois com math.isclose().
  • O cupom é comparado diretamente e depois com upper() aplicado ao texto digitado.
  • A última linha usa >= com o total arredondado para 2 casas por round().
  • Cada comparação imprime o bool resultante, sem if.
código inicial
# caixa.py: conferir uma venda com operadores de comparação.
import math

caneta = 1.10
borracha = 2.20
valor_pago = 3.30
cupom_digitado = "Volta10"
CUPOM_VALIDO = "VOLTA10"

# calcule o total e faça as comparações
saída esperada
Total calculado: 3.3000000000000003
Conferência com ==: False
Conferência com isclose: True
Cupom igual sem tratar: False
Cupom igual com upper(): True
Pagou pelo menos o total? True
Ver dica

Imprima o total antes de comparar: o número que aparece explica por que a igualdade exata não funciona.

Ver resposta
# caixa.py: conferir uma venda com operadores de comparação.
import math

caneta = 1.10
borracha = 2.20
valor_pago = 3.30
cupom_digitado = "Volta10"
CUPOM_VALIDO = "VOLTA10"

total = caneta + borracha
print("Total calculado:", total)

# == compara o float exato; isclose aceita o erro de arredondamento.
print("Conferência com ==:", total == valor_pago)
print("Conferência com isclose:", math.isclose(total, valor_pago))

# O cupom é comparado sem diferenciar maiúsculas de minúsculas.
print("Cupom igual sem tratar:", cupom_digitado == CUPOM_VALIDO)
print("Cupom igual com upper():", cupom_digitado.upper() == CUPOM_VALIDO)

# Comparações de ordem também devolvem bool.
print("Pagou pelo menos o total?", valor_pago >= round(total, 2))

Passo a passo

  1. import math traz o módulo da biblioteca padrão que tem a função math.isclose().
  2. total = caneta + borracha soma dois float; como 1.10 e 2.20 não têm representação binária exata, o total fica 3.3000000000000003.
  3. total == valor_pago compara os valores exatos e dá False, mesmo com o cliente tendo pago o valor certo.
  4. math.isclose(total, valor_pago) considera iguais dois números com diferença relativa minúscula (por padrão, 1 parte em um bilhão) e devolve True.
  5. cupom_digitado == CUPOM_VALIDO diferencia maiúsculas de minúsculas, por isso "Volta10" e "VOLTA10" não são iguais.
  6. cupom_digitado.upper() == CUPOM_VALIDO põe o texto digitado em maiúsculas antes de comparar, e a comparação passa a dar True.
  7. valor_pago >= round(total, 2) arredonda o total para centavos antes de comparar a ordem, evitando que o resíduo de 0.0000000000000003 atrapalhe.

Por que funciona

Todo operador de comparação devolve um bool, que pode ser impresso, guardado numa variável ou usado num if. O cuidado está no que é comparado: float carrega erro de arredondamento, então a igualdade exata falha em contas com casas decimais, e textos são comparados caractere a caractere, com maiúsculas e minúsculas diferentes.

A solução corrige cada caso na hora de comparar: math.isclose() (ou round()) para números e upper() para textos.

Erros comuns

  • if total == 3.3: para validar o pagamento: o caixa recusaria uma venda correta. Compare float com math.isclose() ou arredonde antes.
  • total = 3.30: escrever 3.30 não guarda o zero final nem corrige nada; 3.3, 3.30 e 3.300 são o mesmo float.
  • cupom_digitado.upper == CUPOM_VALIDO: sem os parênteses, compara o próprio método com um texto e dá sempre False. Chame o método com upper().
  • total = valor_pago: com um só = você atribui em vez de comparar. A comparação usa ==.

Outra forma de resolver

Para dinheiro, a forma mais segura é trabalhar com centavos inteiros (110 + 220 == 330 dá True) ou com decimal.Decimal("1.10"), que guarda as casas decimais exatamente. É a escolha certa em sistemas de pagamento; math.isclose() resolve bem em cálculos rápidos.

Saída esperada

Total calculado: 3.3000000000000003
Conferência com ==: False
Conferência com isclose: True
Cupom igual sem tratar: False
Cupom igual com upper(): True
Pagou pelo menos o total? True

03Situação no boletim com operadores lógicosDesafio

Escreva situacao(nome, apelido, soma_notas, qtd_provas, fez_trabalho, fez_feira), que devolve como o aluno é chamado (o apelido, se houver), se foi aprovado (média de pelo menos 7), se vai para a recuperação (fez prova e não passou) e se ganha bônus (fez exatamente uma das duas atividades extras). Um aluno sem provas não pode causar divisão por zero.

↳ Requisitos
  • O nome exibido é obtido com apelido or nome, sem if.
  • A aprovação usa and em curto-circuito com qtd_provas > 0 à esquerda da divisão.
  • A recuperação usa not aprovado combinado com and, e o bônus usa != entre os dois bool.
  • situacao() devolve o texto com return e só a main(), chamada sob if __name__ == "__main__":, imprime.
código inicial
# boletim.py: situação de alunos com and, or, not e !=.
MEDIA_APROVACAO = 7


def situacao(nome, apelido, soma_notas, qtd_provas, fez_trabalho, fez_feira):
    # calcule chamado, aprovado, recuperacao e bonus sem usar if
    return ""


def main():
    print(situacao("Beatriz Souza", "Bia", 24.0, 3, True, False))
    print(situacao("Gustavo Reis", "", 15.0, 3, True, True))
    print(situacao("Laura Mendes", "", 0.0, 0, False, True))
    print(situacao("Pedro Alves", "Pedrinho", 13.5, 2, False, False))


if __name__ == "__main__":
    main()
saída esperada
Bia: aprovado=True, recuperação=False, bônus=True
Gustavo Reis: aprovado=False, recuperação=True, bônus=False
Laura Mendes: aprovado=False, recuperação=False, bônus=True
Pedrinho: aprovado=False, recuperação=True, bônus=False
Ver dica

O and só olha o lado direito quando o esquerdo é verdadeiro; e para "um ou outro, mas não os dois", compare os dois booleanos entre si.

Ver resposta
# boletim.py: situação de alunos com and, or, not e !=.
MEDIA_APROVACAO = 7


def situacao(nome, apelido, soma_notas, qtd_provas, fez_trabalho, fez_feira):
    # or devolve o apelido quando ele não é vazio; senão, o nome.
    chamado = apelido or nome

    # and em curto-circuito: sem provas, a divisão nunca é feita.
    aprovado = qtd_provas > 0 and soma_notas / qtd_provas >= MEDIA_APROVACAO

    # not vem antes de and: "tem provas e NÃO foi aprovado".
    recuperacao = qtd_provas > 0 and not aprovado

    # != entre dois bool funciona como "ou exclusivo".
    bonus = fez_trabalho != fez_feira

    return (
        f"{chamado}: aprovado={aprovado}, "
        f"recuperação={recuperacao}, bônus={bonus}"
    )


def main():
    print(situacao("Beatriz Souza", "Bia", 24.0, 3, True, False))
    print(situacao("Gustavo Reis", "", 15.0, 3, True, True))
    print(situacao("Laura Mendes", "", 0.0, 0, False, True))
    print(situacao("Pedro Alves", "Pedrinho", 13.5, 2, False, False))


if __name__ == "__main__":
    main()

Passo a passo

  1. MEDIA_APROVACAO = 7 fica no topo para que a regra apareça num lugar só.
  2. chamado = apelido or nome: o or devolve o primeiro operando verdadeiro. Como o texto vazio é falso, quem não tem apelido é chamado pelo nome.
  3. qtd_provas > 0 and soma_notas / qtd_provas >= MEDIA_APROVACAO: quando não há provas, a primeira parte é False e o and para ali, sem chegar à divisão por zero.
  4. Na mesma linha, / é calculado antes de >=, e as comparações antes do and: os aritméticos têm a maior precedência, depois as comparações e por último os lógicos.
  5. qtd_provas > 0 and not aprovado: o not se aplica só a aprovado, porque tem precedência maior que o and. Quem não fez prova não vai para a recuperação.
  6. fez_trabalho != fez_feira é True quando exatamente uma das duas atividades foi feita: é o "ou exclusivo" entre dois bool.
  7. A função devolve o texto com return, montado com duas f-strings vizinhas que o Python junta numa só, e a main() faz a impressão.

Por que funciona

Os operadores lógicos do Python avaliam da esquerda para a direita e param assim que o resultado está decidido (curto-circuito). Isso permite usar o and como guarda (só divide se houver provas) e o or como valor padrão (apelido ou nome), sem nenhum if.

A ordem de precedência (aritméticos, depois comparações, depois not, and e or) faz cada expressão ser lida como a frase da regra, e o != entre booleanos cobre o caso "um ou outro, mas não os dois", que não tem operador lógico próprio.

Erros comuns

  • aprovado = soma_notas / qtd_provas >= MEDIA_APROVACAO and qtd_provas > 0: a divisão vem primeiro e Laura provoca ZeroDivisionError. A guarda precisa ficar à esquerda do and.
  • bonus = fez_trabalho or fez_feira: Gustavo, que fez as duas atividades, ganharia o bônus. O or aceita os dois verdadeiros; para "exatamente um", use !=.
  • recuperacao = not qtd_provas > 0 and aprovado: o not passa a negar a comparação, e a regra muda completamente. Coloque o not junto do valor que deve ser invertido.
  • chamado = apelido and nome: o and devolve o segundo operando quando o primeiro é verdadeiro, então Bia seria chamada de "Beatriz Souza". O valor padrão se faz com or.

Outra forma de resolver

Os mesmos resultados podem ser escritos com if/else: chamado = apelido if apelido else nome e um if qtd_provas > 0: antes da divisão. Essa forma é preferível quando a regra tem muitos passos; com uma ou duas condições, o curto-circuito de and e or é idiomático e mais curto.

Saída esperada

Bia: aprovado=True, recuperação=False, bônus=True
Gustavo Reis: aprovado=False, recuperação=True, bônus=False
Laura Mendes: aprovado=False, recuperação=False, bônus=True
Pedrinho: aprovado=False, recuperação=True, bônus=False
← Anterior na trilha de PythonDecisões com condicionais

Últimas lições

Ver o arquivo completo →