Se variáveis são os recipientes que guardam dados, os operadores são as ferramentas que permitem trabalhar com esses dados. Python oferece um conjunto rico e expressivo de operadores — alguns familiares para quem já programou em outra linguagem, outros exclusivos do Python.
Operadores Aritméticos
Os mais básicos — realizam cálculos matemáticos:
a = 10
b = 3
print(a + b) # 13 — adição
print(a - b) # 7 — subtração
print(a * b) # 30 — multiplicação
print(a / b) # 3.3333... — divisão real (sempre retorna float)
print(a // b) # 3 — divisão inteira (descarta o decimal)
print(a % b) # 1 — módulo (resto da divisão)
print(a ** b) # 1000 — potenciação
A divisão com / sempre retorna float em Python 3 — isso foi uma das correções feitas em relação ao Python 2, onde 10 / 3 retornava 3.
Cuidado com a descrição de // como "descartar o decimal": ela só vale enquanto os dois números são positivos. O que o operador faz é arredondar para baixo — e para baixo significa na direção do infinito negativo, de modo que -10 // 3 não dá -3, e sim -4. O % acompanha, porque os dois precisam ser coerentes entre si: em Python o resto herda o sinal do divisor, e -10 % 3 é 2, não -1. Quem vem de C, de Java ou de JavaScript tropeça aqui, porque nessas linguagens a divisão trunca e o resto herda o sinal do dividendo. Se a intenção é mesmo truncar, peça isso explicitamente com int(a / b).
O operador ** é especialmente útil:
raiz_quadrada = 25 ** 0.5
print(raiz_quadrada) # 5.0
cubo = 4 ** 3
print(cubo) # 64
Operadores de Comparação
Retornam sempre True ou False:
x = 10
y = 20
print(x == y) # False — igual a
print(x != y) # True — diferente de
print(x < y) # True — menor que
print(x > y) # False — maior que
print(x <= 10) # True — menor ou igual
print(x >= 10) # True — maior ou igual
Atenção ao erro clássico de confundir = (atribuição) com == (comparação):
x = 5 # atribui o valor 5 a x
x == 5 # compara x com 5, retorna True
E uma facilidade que Python tem e quase nenhuma outra linguagem oferece: as comparações podem ser encadeadas, do mesmo jeito que na notação matemática.
idade = 25
# em Python, escreve-se como se lê
if 18 <= idade < 65:
print("idade de trabalho")
# em vez do que seria preciso em outra linguagem
if idade >= 18 and idade < 65:
print("idade de trabalho")
Não é só economia de escrita: no encadeamento o valor do meio é avaliado uma única vez, o que passa a importar quando ele é uma chamada de função.
Operadores Lógicos
Combinam expressões booleanas:
idade = 25
tem_carteira = True
# and — verdadeiro se ambos forem verdadeiros
pode_dirigir = idade >= 18 and tem_carteira
print(pode_dirigir) # True
# or — verdadeiro se pelo menos um for verdadeiro
tem_acesso = idade >= 18 or tem_carteira
print(tem_acesso) # True
# not — inverte o valor
nao_pode = not pode_dirigir
print(nao_pode) # False
Python avalia expressões com curto-circuito: em um and, se o primeiro operando for False, o segundo nem é avaliado. Em um or, se o primeiro for True, o segundo é ignorado. Isso é importante para evitar erros:
lista = []
# sem curto-circuito, lista[0] causaria IndexError
if lista and lista[0] == "Python":
print("Encontrado")
Do curto-circuito decorre um detalhe que surpreende quase todo mundo: and e or não devolvem True ou False — devolvem um dos operandos. O or entrega o primeiro que for verdadeiro; o and, o primeiro que for falso, ou o último se nenhum for. Por isso 0 or "x" resulta em "x", e "a" and "b" resulta em "b". Isso se usa de propósito para dar valor padrão a uma variável, no lugar do ternário de outras linguagens — e vira armadilha quando o valor legítimo é falso: quantidade or 10 devolve 10 quando a quantidade é 0, que era justamente o número a guardar. Nesse caso o teste certo é if quantidade is None.
Operadores de Atribuição
Além do = básico, Python oferece formas compactas de atualizar variáveis:
x = 10
x += 5 # equivale a x = x + 5 → 15
x -= 3 # equivale a x = x - 3 → 12
x *= 2 # equivale a x = x * 2 → 24
x /= 4 # equivale a x = x / 4 → 6.0
x //= 2 # equivale a x = x // 2 → 3.0
x **= 3 # equivale a x = x ** 3 → 27.0
x %= 5 # equivale a x = x % 5 → 2.0
Operadores de Identidade e Pertinência
Dois operadores que não existem em muitas linguagens, mas são muito usados em Python:
is e is not — verificam se dois nomes apontam para o mesmo objeto na memória:
a = [1, 2, 3]
b = a # b aponta para o mesmo objeto
c = [1, 2, 3] # c é um objeto diferente, mas com o mesmo conteúdo
print(a is b) # True
print(a is c) # False
print(a == c) # True — conteúdo igual, objetos diferentes
in e not in — verificam se um valor está contido em uma sequência:
frutas = ["maçã", "banana", "laranja"]
print("banana" in frutas) # True
print("uva" in frutas) # False
print("uva" not in frutas) # True
frase = "Python é incrível"
print("Python" in frase) # True
Precedência de Operadores
Quando há múltiplos operadores em uma expressão, Python segue uma ordem de precedência. Da mais alta para a mais baixa:
1. ** (potenciação)
2. +x, -x (sinais unários)
3. *, /, //, % (multiplicação, divisão)
4. +, - (adição, subtração)
5. ==, !=, <, > (comparação)
6. not (negação lógica)
7. and (e lógico)
8. or (ou lógico)
Exemplos:
print(2 + 3 * 4) # 14, não 20 — multiplicação primeiro
print((2 + 3) * 4) # 20 — parênteses forçam a ordem
print(2 ** 3 ** 2) # 512 — potenciação associa da direita: 2 ** (3**2) = 2**9
A recomendação é sempre usar parênteses quando a expressão tiver risco de ambiguidade — o código fica mais legível e você evita surpresas.
Expressões com Strings
Strings também aceitam alguns operadores:
# Concatenação
primeiro = "Python"
segundo = " é incrível"
print(primeiro + segundo) # Python é incrível
# Repetição
linha = "-" * 40
print(linha) # ----------------------------------------
# Comparação (ordem lexicográfica)
print("apple" < "banana") # True
print("Z" < "a") # True — maiúsculas têm valor menor
Se houver uma coisa a levar desta parte, que seja a desconfiança com as descrições fáceis. "Divisão inteira descarta o decimal" e "os operadores lógicos devolvem verdadeiro ou falso" são frases que funcionam nos exemplos de sala de aula e falham no primeiro dado real — a primeira quando aparece um número negativo, a segunda quando o valor legítimo é zero ou uma lista vazia. Python tem razões coerentes para ambos os comportamentos, e as duas decisões se sustentam: o piso mantém a identidade entre a divisão e o resto, e o curto-circuito devolvendo o operando é o que permite escrever valor padrão em uma linha.
O resto é conveniência que vale conhecer de cor. O encadeamento de comparações deixa a condição parecida com a notação matemática e avalia o valor do meio uma vez só. O in transforma uma busca em uma palavra. E a distinção entre is e ==, que parece pedantismo enquanto os exemplos são inteiros pequenos, é a diferença entre perguntar se dois nomes apontam para o mesmo objeto e perguntar se dois objetos valem a mesma coisa — duas perguntas que só coincidem por acidente.
Fontes e leituras recomendadas
- Operadores do Python — https://docs.python.org/3/reference/expressions.html#operator-precedence
- Operadores de identidade e pertinência — https://docs.python.org/3/library/stdtypes.html#comparisons
- PEP 8 sobre expressões — https://peps.python.org/pep-0008/#programming-recommendations
- MATTHES, Eric. Python Crash Course. 3. ed. No Starch Press, 2023. Cap. 2–3.
- LUTZ, Mark. Learning Python. 5. ed. O'Reilly Media, 2013. Cap. 5.
- RAMALHO, Luciano. Fluent Python. 2. ed. O'Reilly Media, 2022. Cap. 1.
Exercícios
Exercício 1
Você escreve uma função que distribui itens em páginas: paginas = total // por_pagina. Os testes passam. Em produção, um relatório com saldo negativo produz um número de páginas que ninguém consegue explicar. O que aconteceu?
Ver resposta
✓ Resposta: O // não trunca: ele arredonda para baixo, na direção do infinito negativo. Com valores positivos as duas descrições coincidem e o defeito fica invisível — 10 // 3 é 3 de qualquer jeito. Com um negativo elas divergem: -10 // 3 devolve -4, e não -3, porque menos quatro é o maior inteiro que não passa de menos três e um terço. O % acompanha pela mesma regra, e o resto herda o sinal do divisor: -10 % 3 é 2. Isso não é excentricidade — é o que mantém verdadeira a identidade (a // b) * b + (a % b) == a, que em C e em Java só vale porque lá as duas operações combinam de outro jeito, truncando e herdando o sinal do dividendo. A consequência prática é ótima para um caso muito comum: indice % len(lista) em Python sempre devolve um índice válido, mesmo com índice negativo, enquanto em C o mesmo cálculo devolve um número negativo e estoura o vetor. Para o caso da paginação, se a intenção é truncar, escreva int(total / por_pagina); se a intenção é arredondar para cima, o idioma é -(-total // por_pagina), ou math.ceil com a divisão real.
Exercício 2
Um formulário tem um campo de quantidade opcional. O código escreve quantidade = entrada or 10 para aplicar o padrão quando o campo vem vazio. Funciona quase sempre. Quando falha, e por quê?
Ver resposta
✓ Resposta: Falha quando o usuário digita zero — e passa a valer 10, apagando em silêncio uma quantidade que ele informou de propósito. A causa é que or não testa "está preenchido": testa veracidade, e em Python são falsos o 0, o 0.0, a string vazia, a lista vazia, o dicionário vazio e o None. Os seis caem no mesmo balde, embora só um deles signifique "não informado". Vale lembrar, de passagem, que o or também não devolve um booleano: ele entrega o primeiro operando verdadeiro, ou o último se nenhum for — é por isso que a construção funciona como valor padrão. O conserto é testar exatamente o que se quer saber: quantidade = entrada if entrada is not None else 10. O is not None é literal e não confunde zero com ausência. O mesmo defeito aparece com outra roupa em if not lista: quando se queria perguntar se a lista existe, e não se ela está vazia — uma lista vazia e um None respondem igual ali, e quase sempre significam coisas diferentes no domínio.
Exercício 3
O artigo mostra que a is b é True para dois nomes da mesma lista e False para listas iguais mas distintas. Um colega testa com números, escreve a = 257 e b = 257, e a is b devolve True. Isso significa que se pode usar is para comparar inteiros?
Ver resposta
✓ Resposta: Não — e o que torna o caso instrutivo é justamente ele ter dado True. O CPython mantém um cache de inteiros pequenos, de -5 a 256, reaproveitando os mesmos objetos; fora dessa faixa, cada valor deveria ser um objeto novo. Só que há um segundo mecanismo: quando o compilador vê dois literais iguais dentro do mesmo bloco de código, ele os unifica numa constante só. Por isso o teste dá True no mesmo arquivo e pode dar False se os valores vierem de lugares diferentes — de uma soma, de uma leitura de arquivo, de uma linha separada do REPL. A conclusão correta não é "funciona até 256": é que o resultado de is com números é detalhe de implementação, e não faz parte do contrato da linguagem. Código que depende disso funciona por acidente e quebra sem aviso. A regra prática é curta: is serve para perguntar se dois nomes apontam para o mesmo objeto, e na prática se usa quase só com None, True e False — que são objetos únicos garantidos. Para valor, ==. O próprio Python avisa: comparar um literal com is dispara um SyntaxWarning.
Exercício 4
Você precisa validar que uma nota está entre 0 e 10. Compare if 0 <= nota <= 10: com if nota >= 0 and nota <= 10:. Há diferença além do estilo?
Ver resposta
✓ Resposta: Há uma, e ela aparece quando o valor do meio não é uma variável. No encadeamento, o termo central é avaliado uma única vez: escrever 0 <= calcular_nota() <= 10 chama a função uma vez, enquanto calcular_nota() >= 0 and calcular_nota() <= 10 chama duas — o que dobra o custo e, pior, pode dar resultados incoerentes se a função não for determinística ou tiver efeito colateral. O encadeamento também preserva o curto-circuito: se a primeira comparação for falsa, a segunda nem acontece. Fora isso, é legibilidade, e vale muito: 18 <= idade < 65 se lê na ordem em que se pensa, e deixa claro num relance que um limite é inclusivo e o outro não. Um aviso sobre os limites do recurso: o encadeamento é açúcar sintático de conjunção, então a < b > c é sintaticamente válido e quase sempre um erro de digitação — significa a < b and b > c, que não é o que ninguém queria escrever. E cuidado ao encadear in ou is junto de comparações, porque eles entram na mesma regra: x in lista == True não faz o que parece.
Exercício 5
Explique por que -2 ** 2 devolve -4, e por que 2 ** 3 ** 2 devolve 512 e não 64. O que essas duas respostas têm em comum?
Ver resposta
✓ Resposta: As duas saem da mesma decisão: o ** é o operador de maior precedência da tabela, e ele é o único dos aritméticos que associa da direita para a esquerda. Em -2 ** 2, o sinal de menos não faz parte do número — é o operador unário de negação, que tem precedência menor que a potenciação. Python calcula primeiro 2 ** 2 e depois nega o resultado: -(2 ** 2), ou seja, -4. Quem quer o quadrado de menos dois precisa dos parênteses: (-2) ** 2 devolve 4. Em 2 ** 3 ** 2, a associatividade à direita faz a conta virar 2 ** (3 ** 2), que é 2 ** 9, ou 512 — e não (2 ** 3) ** 2, que daria 64. Essa escolha não é arbitrária: é a convenção da notação matemática, onde uma torre de expoentes se resolve de cima para baixo. Há um detalhe fino que confirma a regra: o unário é permitido do lado direito do ** sem parênteses, e por isso 2 ** -1 é válido e devolve 0.5. O que as duas respostas têm em comum, no fim, é a lição prática: precedência que se precisa lembrar é precedência que se deve escrever com parênteses, porque quem lê o código depois não vai consultar a tabela.