Operadores e Expressões

Operadores e Expressões

Os operadores parecem a parte trivial da linguagem, e guardam algumas das surpresas mais caras: a divisão inteira arredonda para baixo em vez de truncar, o resto herda o sinal do divisor e o and devolve um operando, não um booleano. Com o encadeamento de comparações, que quase nenhuma outra linguagem tem.
Python

• • 13 min de leitura

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

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.

Comentários

Mais em Python

Introdução ao Desenvolvimento Web com Flask
Introdução ao Desenvolvimento Web com Flask

Flask começa com uma rota e uma função, e os erros aparecem no que ele deixa…

Listas: criação, manipulação e métodos
Listas: criação, manipulação e métodos

A estrutura que aparece em praticamente todo programa Python: criação, índices…

A História do Python e os Primeiros Passos
A História do Python e os Primeiros Passos

De um projeto de férias de Natal em 1989 à linguagem que hoje sai em versão…