Operadores de comparação e identidade: == vs is
1. Introdução aos operadores de comparação em Python
Operadores de comparação são fundamentais na lógica de programação, permitindo que tomemos decisões baseadas em relações entre valores. Python oferece um conjunto completo desses operadores: == (igual), != (diferente), < (menor), > (maior), <= (menor ou igual) e >= (maior ou igual).
No entanto, dois operadores frequentemente causam confusão entre iniciantes e até mesmo desenvolvedores experientes: == e is. Embora ambos pareçam verificar "igualdade", eles operam em níveis completamente diferentes. O operador == compara valores, enquanto is compara identidade de objetos. Compreender essa distinção é crucial para escrever código Python correto e eficiente.
2. O operador ==: comparando valores
O operador == verifica se dois objetos possuem o mesmo valor ou conteúdo. Ele não se importa se são objetos diferentes na memória; apenas avalia se seus dados são equivalentes.
# Comparações simples com ==
print(5 == 5) # True: mesmo valor numérico
print("python" == "python") # True: mesmo conteúdo textual
print([1, 2] == [1, 2]) # True: listas com mesmos elementos
# Comparação entre tipos diferentes
print(5 == 5.0) # True: Python converte automaticamente
print("5" == 5) # False: string vs int
Um caso clássico que demonstra as limitações de == com floats:
# Problema de precisão com floats
print(0.1 + 0.2 == 0.3) # False! Surpreendente, não?
print(0.1 + 0.2) # 0.30000000000000004
Isso ocorre porque números de ponto flutuante são representados em binário, e algumas frações decimais não podem ser representadas exatamente. Para comparações precisas com floats, use math.isclose().
3. O operador is: comparando identidade de objetos
O operador is verifica se duas variáveis referenciam exatamente o mesmo objeto na memória. Cada objeto em Python possui um identificador único, acessível via id().
# Entendendo identidade de objetos
a = [1, 2]
b = a # b aponta para o mesmo objeto que a
c = [1, 2] # c é um novo objeto com mesmo conteúdo
print(a is b) # True: mesmo objeto
print(a is c) # False: objetos diferentes
print(id(a), id(b), id(c)) # a e b compartilham o mesmo id
Note que a is [1, 2] sempre retorna False, pois [1, 2] cria um novo objeto a cada execução.
4. Quando == e is concordam (e quando divergem)
Casos de concordância
Python aplica uma otimização chamada interning para alguns objetos imutáveis. Isso faz com que objetos com o mesmo valor compartilhem a mesma identidade em certos casos:
# Interning de inteiros pequenos
a = 5
b = 5
print(a == b) # True
print(a is b) # True (devido ao interning)
# Interning de strings simples
x = "hello"
y = "hello"
print(x == y) # True
print(x is y) # True (strings curtas são internadas)
Casos de divergência
Para objetos mutáveis como listas, dicionários e conjuntos, == e is frequentemente divergem:
# Divergência clássica com listas
a = [1, 2]
b = [1, 2]
print(a == b) # True: mesmo conteúdo
print(a is b) # False: objetos diferentes na memória
# Com dicionários
d1 = {"nome": "Ana", "idade": 30}
d2 = {"nome": "Ana", "idade": 30}
print(d1 == d2) # True
print(d1 is d2) # False
5. O fenômeno do interning em Python
Interning é uma técnica de otimização onde Python reutiliza objetos imutáveis idênticos para economizar memória. Isso é mais visível com inteiros pequenos e strings simples.
# Interning de inteiros: limite visível
a = 256
b = 256
print(a is b) # True (dentro da faixa -5 a 256)
c = 257
d = 257
print(c is d) # False (fora da faixa de interning)
# Interning de strings: depende do conteúdo
s1 = "Python"
s2 = "Python"
print(s1 is s2) # True (strings alfanuméricas curtas)
s3 = "Python " * 100 # String longa
s4 = "Python " * 100
print(s3 is s4) # False (muito longa para interning automático)
Importante: Nunca confie no interning para lógica de programa. Sempre use == para comparar valores e is apenas para identidade.
6. Boas práticas: quando usar == e quando usar is
Regras práticas:
-
Use
==para comparar valores: números, strings, listas, dicionários, etc. -
Use
ispara comparar com singletons:None,True,False.
# Correto: comparando com None
def processar_dados(dados):
if dados is None: # Padrão recomendado
return "Sem dados"
return f"Dados processados: {dados}"
# Evite: == None funciona, mas é menos idiomático
if dados == None: # Funciona, mas não é recomendado
pass
# Comparação com booleanos
flag = True
if flag is True: # Explícito e claro
print("Ativo")
- Cuidado com objetos mutáveis: Sempre use
==para verificar igualdade de conteúdo.
# Armadilha comum
lista_a = [1, 2, 3]
lista_b = [1, 2, 3]
if lista_a == lista_b: # Correto: comparando conteúdo
print("Mesmos valores")
if lista_a is lista_b: # Quase sempre False para listas diferentes
print("Mesmo objeto") # Raramente executado
- Para enums e objetos personalizados: Use
ispara comparar membros de enumeração e==para comparar valores de atributos.
7. O método __eq__: personalizando a comparação com ==
Podemos definir como == se comporta para nossas próprias classes sobrescrevendo o método __eq__.
class Pessoa:
def __init__(self, nome, cpf):
self.nome = nome
self.cpf = cpf
def __eq__(self, other):
if not isinstance(other, Pessoa):
return NotImplemented
# Duas pessoas são "iguais" se tiverem o mesmo CPF
return self.cpf == other.cpf
def __hash__(self):
# Importante: objetos iguais devem ter o mesmo hash
return hash(self.cpf)
# Testando
p1 = Pessoa("Ana", "123.456.789-00")
p2 = Pessoa("Ana Silva", "123.456.789-00") # Mesmo CPF, nome diferente
p3 = Pessoa("Carlos", "987.654.321-00")
print(p1 == p2) # True (mesmo CPF)
print(p1 == p3) # False (CPFs diferentes)
print(p1 is p2) # False (objetos diferentes)
# Uso em conjunto (depende de __hash__)
conjunto = {p1, p2, p3}
print(len(conjunto)) # 2 (p1 e p2 são considerados iguais)
8. Resumo e dicas finais
| Operador | Compara | Exemplo típico | Uso recomendado |
|---|---|---|---|
== |
Valor/conteúdo | a == b |
Dados em geral |
is |
Identidade (memória) | a is None |
Singletons |
Checklist para evitar erros comuns:
- [ ] Para comparar números, strings ou coleções → use
== - [ ] Para verificar se uma variável é
None→ useis None - [ ] Para verificar booleanos → prefira
if variavel:em vez deif variavel is True: - [ ] Nunca confie em interning para lógica de programa
- [ ] Ao criar classes, implemente
__eq__e__hash__juntos se for usar a classe em conjuntos ou dicionários
Exercício prático:
Analise cada comparação e decida se deve usar == ou is:
# 1. Verificar se duas strings têm o mesmo texto
texto1 = "Python"
texto2 = "python".upper()
# Resposta: texto1 == texto2
# 2. Verificar se uma variável não tem valor atribuído
var = None
# Resposta: var is None
# 3. Verificar se duas listas têm os mesmos elementos
lista1 = [1, 2, 3]
lista2 = [1, 2, 3]
# Resposta: lista1 == lista2
# 4. Verificar se duas variáveis apontam para o mesmo objeto
a = [1, 2]
b = a
# Resposta: a is b
Lembre-se: == pergunta "os valores são equivalentes?", enquanto is pergunta "é exatamente o mesmo objeto?". Dominar essa diferença é um marco no aprendizado de Python.
Referências
- Python Documentation: Comparisons — Documentação oficial sobre operadores de comparação em Python, incluindo
==,!=,iseis not. - Python Documentation:
isoperator — Seção específica sobre o operadorise identidade de objetos. - Real Python: Python 'is' vs '==': What's the Difference? — Tutorial completo explicando as diferenças entre
ise==com exemplos práticos. - GeeksforGeeks: Difference between == and is operator in Python — Artigo técnico detalhando as diferenças e casos de uso, incluindo interning.
- Stack Overflow: Understanding Python's "is" operator — Discussão comunitária de alto nível sobre o operador
ise suas nuances. - Python Wiki: Interning — Explicação sobre o fenômeno de interning em Python e como ele afeta a comparação com
is.