== vs is en Python: diferencia entre igualdad e identidad

Publicado el: 12/07/2026
Tempo de leitura: 4 minutos
Diferença entre operadores is e == em Python

Los operadores == e is pueden parecer equivalentes cuando se prueban con valores pequeños, pero responden preguntas diferentes. == comprueba si dos objetos tienen valores equivalentes, mientras que is comprueba si ambas referencias apuntan exactamente al mismo objeto. Confundir igualdad con identidad produce errores sutiles, especialmente con listas, strings, copias y valores opcionales.

Para comprender el tema, revisa la guía de operadores en Python, el artículo sobre listas y copias, la explicación de tipos de datos, la guía de clases y objetos y el tutorial de manejo de errores.

Las fuentes externas principales son la referencia oficial de comparaciones y la documentación oficial del modelo de datos de Python.

Igualdad de valores con ==

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)  # True

Las listas contienen los mismos elementos en el mismo orden, por lo que se consideran iguales. Python utiliza el método especial __eq__() del tipo para decidir el resultado.

Identidad con is

a = [1, 2, 3]
b = [1, 2, 3]

print(a is b)  # False

Aunque sus valores coinciden, son dos listas creadas por separado. Cada una ocupa su propia identidad durante la ejecución.

Dos nombres para el mismo objeto

a = [1, 2, 3]
b = a

print(a == b)  # True
print(a is b)  # True

b.append(4)
print(a)

La asignación no crea una copia. a y b apuntan a la misma lista, por lo que una modificación realizada mediante cualquiera de los nombres se observa desde el otro.

Comprobar la identidad con id()

a = {"activo": True}
b = a
c = {"activo": True}

print(id(a) == id(b))
print(id(a) == id(c))

id() devuelve un identificador único durante la vida del objeto. Se utiliza para aprendizaje y diagnóstico, pero el código normal debe expresar identidad con is.

La regla importante para None

resultado = None

if resultado is None:
    print("No existe un resultado")

None es un objeto único utilizado para representar ausencia de valor. La recomendación estándar es comparar con is None o is not None.

if resultado is not None:
    procesar(resultado)

Además de ser más claro, este patrón evita depender de una implementación personalizada de __eq__().

No uses is con strings y números

nombre = "Python"

if nombre == "Python":
    print("Coincide")

La comparación correcta para valores es ==. Algunas pruebas con strings cortos o enteros pequeños pueden hacer que is devuelva True debido a optimizaciones internas, pero ese comportamiento no debe utilizarse como lógica del programa.

Por qué algunas pruebas engañan

a = 10
b = 10
print(a is b)

Un intérprete puede reutilizar ciertos objetos inmutables. Esto se conoce como interning o caché interna. El detalle depende del intérprete, del contexto y de la compilación. Que dos valores compartan identidad en una prueba no convierte is en un operador de igualdad.

Copias superficiales

original = [[1, 2], [3, 4]]
copia = original.copy()

print(original == copia)  # True
print(original is copia)  # False
print(original[0] is copia[0])  # True

La lista exterior es nueva, pero sus elementos internos siguen compartidos. Por eso se llama copia superficial.

copia[0].append(99)
print(original)

La modificación afecta a la lista interna observada por ambos objetos.

Copias profundas

from copy import deepcopy

original = [[1, 2], [3, 4]]
copia = deepcopy(original)

print(original == copia)
print(original is copia)
print(original[0] is copia[0])

deepcopy intenta copiar también los objetos anidados. No siempre es necesario y puede ser costoso o inapropiado para recursos como archivos, conexiones y objetos con estado externo.

Objetos personalizados y __eq__

class Producto:
    def __init__(self, codigo, nombre):
        self.codigo = codigo
        self.nombre = nombre

    def __eq__(self, otro):
        if not isinstance(otro, Producto):
            return NotImplemented
        return self.codigo == otro.codigo


p1 = Producto(10, "Teclado")
p2 = Producto(10, "Teclado mecánico")

print(p1 == p2)  # True
print(p1 is p2)  # False

La clase define igualdad según el código. Son instancias diferentes, pero representan el mismo producto según la regla del dominio.

Devolver NotImplemented

Cuando el otro objeto no es compatible, __eq__() debería devolver NotImplemented en lugar de lanzar una excepción o devolver siempre False. Esto permite que Python intente la comparación inversa y maneje correctamente tipos diferentes.

Igualdad en dataclasses

from dataclasses import dataclass

@dataclass
class Punto:
    x: int
    y: int

p1 = Punto(2, 3)
p2 = Punto(2, 3)

print(p1 == p2)
print(p1 is p2)

Las dataclasses generan un método de igualdad basado en campos, salvo que se configure lo contrario.

Comparaciones con booleanos

activo = True

if activo:
    print("Está activo")

No necesitas escribir activo == True ni activo is True en la mayoría de condiciones. Utiliza directamente el valor booleano. Sin embargo, si una variable puede ser True, False o None, una comprobación de identidad puede expresar una diferencia intencional:

if estado is None:
    print("Sin configurar")
elif estado:
    print("Activado")
else:
    print("Desactivado")

Sentinelas personalizados

A veces None es un valor válido y necesitas distinguir “no proporcionado”:

NO_PROPORCIONADO = object()


def configurar(valor=NO_PROPORCIONADO):
    if valor is NO_PROPORCIONADO:
        return "Usar configuración predeterminada"
    if valor is None:
        return "Desactivar configuración"
    return f"Configurar: {valor}"

Un objeto creado como sentinela se compara por identidad. Nadie puede producirlo accidentalmente desde una entrada común.

Igualdad en colecciones

lista = [1, 2, 3]
tupla = (1, 2, 3)

print(lista == [1, 2, 3])
print(lista == tupla)

Cada tipo define sus reglas. Listas y tuplas con los mismos elementos no se consideran iguales porque son estructuras distintas. Los diccionarios comparan pares clave-valor sin depender del orden de inserción.

NaN y comparaciones inesperadas

nan = float("nan")
print(nan == nan)  # False
print(nan is nan)  # True

NaN sigue reglas especiales de punto flotante y no es igual a sí mismo. Para detectarlo utiliza math.isnan(), no identidad ni igualdad.

Pruebas correctas

def test_listas_equivalentes():
    esperado = [1, 2, 3]
    obtenido = construir_lista()
    assert obtenido == esperado

Las pruebas normalmente verifican resultados por valor. Utiliza identidad cuando el contrato exige devolver el mismo objeto, por ejemplo en una caché o un singleton.

Tabla mental sencilla

Pregunta “¿tienen el mismo valor?” y utiliza ==. Pregunta “¿son exactamente el mismo objeto?” y utiliza is. Para None y sentinelas, usa identidad. Para texto, números, listas, diccionarios y resultados calculados, usa igualdad.

Errores frecuentes

Los errores más comunes son escribir texto is "hola", comparar números con identidad, asumir que una asignación crea una copia y utilizar una copia superficial para estructuras anidadas. También es frecuente implementar __eq__() sin comprobar el tipo o sin devolver NotImplemented.

Conclusión

== compara valores según las reglas del tipo; is compara identidad. Dos objetos pueden ser iguales sin ser el mismo objeto, y dos nombres pueden compartir identidad aunque parezcan variables independientes. Utiliza is None para ausencia, is para sentinelas y == para datos. Esta diferencia evita errores de memoria compartida, comparaciones frágiles y comportamientos que cambian entre ejecuciones.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    notebook com código saindo da tela
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Variables en Python: guía completa para principiantes

    Aprende variables en Python: asignación, nombres, tipos, conversiones, referencias, mutabilidad, alcance, constantes, None y errores frecuentes.

    Ler mais

    Tempo de leitura: 4 minutos
    12/07/2026
    Menu interativo no terminal criado com Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un menú interactivo en el terminal con Python

    Crea un menú interactivo en Python con while, funciones, diccionarios, validación, submenús, persistencia JSON y manejo seguro de errores.

    Ler mais

    Tempo de leitura: 4 minutos
    12/07/2026
    Uso do operador in em Python para verificação em coleções
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Operador in en Python: pertenencia en listas, strings y sets

    Aprende a usar el operador in y not in con listas, strings, diccionarios, sets, generadores y clases personalizadas mediante __contains__.

    Ler mais

    Tempo de leitura: 4 minutos
    12/07/2026
    Ilustração que representa um algoritmo
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Qué es un algoritmo en programación: guía con Python

    Entiende qué es un algoritmo, cómo describirlo con pseudocódigo, analizar su complejidad y convertirlo en funciones Python comprobables.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026
    Leitura e escrita de arquivos CSV em Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Archivos CSV en Python: leer, escribir y procesar datos

    Aprende a leer, escribir, validar y transformar CSV en Python con csv, DictReader, DictWriter, UTF-8, streaming y protección contra errores.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Programador resolvendo problemas com Python
    Fundamentos
    Foto de perfil de Leandro Hirt da Academify

    Lógica de programación con Python para principiantes

    Aprende lógica de programación con Python mediante algoritmos, pseudocódigo, condiciones, bucles, funciones, validación y pruebas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026