Python / Objetos y variables

En Python, un objeto representa datos con un valor y operaciones posibles; una variable es un nombre vinculado a un objeto. x = 100 vincula x con un entero y una nueva asignación cambia el objeto al que se refiere. Asignar no copia objetos automáticamente, por lo que varios nombres pueden compartir una lista.

Nombres, objetos y tipos

El modelo de datos de Python atribuye a los objetos identidad, tipo y valor. El tipo determina sus operaciones y propiedades. La identidad se mantiene mientras el objeto existe; la posibilidad de modificar su valor depende del tipo. Imaginar variables como cajas de tipo fijo no explica bien la reasignación ni las referencias compartidas.

Los ejemplos usan Python 3 y la biblioteca estándar, y sus salidas se comprobaron con Python 3.12.14. Guarda cada código completo en UTF-8 como objects_demo.py y ejecuta python objects_demo.py en un terminal, o python3 según el entorno. Sustituye el contenido para probar cada ejemplo de forma independiente.

value = 100
print(value, type(value).__name__)
value = "hello"
print(value, type(value).__name__)
100 int
hello str

value se refiere primero a un int y después a un str. El objeto entero 100 no ha cambiado de tipo. Una asignación evalúa la expresión de la derecha y vincula el resultado al nombre de la izquierda. type(value) consulta el tipo del objeto actualmente asociado.

Compartir una lista frente a reasignar un nombre

second = first no crea una copia: ambos nombres apuntan a la misma lista. Compara modificar ese objeto compartido con reasignar solo un nombre:

first = [1, 2]
second = first
second.append(3)
print(first)
print(second)
print(first is second)
first = [0]
print(first)
print(second)
print(first is second)
[1, 2, 3]
[1, 2, 3]
True
[0]
[1, 2, 3]
False

append modifica la lista compartida, por lo que first también muestra el 3 añadido. En cambio, first = [0] vincula únicamente first con una lista nueva. second sigue apuntando a la anterior. Distingue el vínculo de un nombre del contenido del objeto.

Operación Significado Efecto en el otro nombre
second = first Añadir un nombre para el mismo objeto Ambos observan cambios posteriores
second.append(3) Modificar la lista La misma lista refleja el cambio
first = [0] Vincular first con otro objeto second conserva su vínculo

Objetos inmutables y +=

Enteros, cadenas y tuplas son inmutables; listas y diccionarios son mutables. Inmutable significa que no puedes cambiar el objeto en el mismo lugar, no que su nombre no pueda recibir otra asignación.

first = 10
second = first
first += 1
print(first)
print(second)
11
10

El entero 10 no se transforma en 11. first queda vinculado al resultado de la suma y second sigue refiriéndose a 10. Con una lista, la misma sintaxis += puede modificar el objeto existente, así que no generalices entre tipos. Las referencias de los elementos de una tupla no se sustituyen, pero una lista contenida en ella sí puede cambiar.

Elegir la profundidad de copia

copy() de una lista crea una lista externa nueva: es una copia superficial. Los objetos internos siguen compartidos. Compárala con copy.deepcopy() usando los mismos datos iniciales:

from copy import deepcopy

original = [[1], [2]]
shallow = original.copy()
deep = deepcopy(original)
shallow[0].append(9)
shallow.append([3])
print(original)
print(shallow)
print(deep)
print(original is shallow)
print(original[0] is shallow[0])
[[1, 9], [2]]
[[1, 9], [2], [3]]
[[1], [2]]
False
True

Añadir 9 a la lista interna desde shallow también aparece en original. Añadir [3] a la lista externa de shallow no aumenta la longitud de original. deep conserva una copia independiente del contenido anidado inicial. Decide si compartir es intencionado y copia solo lo necesario. La copia profunda tiene un coste y no sirve para duplicar archivos o sockets como datos ordinarios.

== compara igualdad; is, identidad

En las listas incorporadas, == compara contenido e is comprueba si es exactamente el mismo objeto. Estas listas se crearon por separado aunque su contenido sea igual:

left = [1, 2]
right = [1, 2]
alias = left
print(left == right)
print(left is right)
print(left is alias)
print(id(left) == id(alias))
missing = None
print(missing is None)
True
False
True
True
True

Usa los operadores de comparación según su propósito. id() devuelve un entero que representa identidad; el número concreto puede variar entre ejecuciones y no tiene por qué ser una dirección de memoria en todas las implementaciones. No compares valores de números o cadenas con is confiando en cachés o reutilización. Usa == para valores e is None para None.

del elimina el vínculo de un nombre

del es una sentencia, no una función. del first elimina ese vínculo. Otro nombre que siga apuntando al objeto permite continuar utilizándolo:

first = [1, 2]
second = first
del first
print(second)
try:
    print(first)
except NameError:
    print("first: NameError")
try:
    del unknown_name
except NameError:
    print("unknown_name: NameError")
[1, 2]
first: NameError
unknown_name: NameError

second sigue mostrando la lista, mientras que leer first genera NameError. Eliminar un nombre desconocido también genera NameError. Según el destino, la sentencia del puede eliminar elementos o atributos, no solo nombres. Borrar un vínculo no garantiza destruir inmediatamente el objeto o liberar su memoria. Cierra archivos con with o close, sin depender de del.

Nombres válidos y legibles

Para caracteres latinos básicos, comienza por una letra o guion bajo y utiliza dígitos después. No se permiten espacios ni guiones, y se distinguen mayúsculas. Python también acepta determinados caracteres Unicode, por lo que los identificadores no se limitan al inglés.

import keyword

for name in ["user_name", "2name", "class", "first-name", "café", "match"]:
    valid = name.isidentifier() and not keyword.iskeyword(name)
    print(name, valid)
print("match soft keyword:", keyword.issoftkeyword("match"))
user_name True
2name False
class False
first-name False
café True
match True
match soft keyword: True

isidentifier() acepta la forma de class, así que comprueba también keyword.iskeyword(). En este entorno, match es una palabra clave contextual, no una palabra reservada en todos los contextos. Consulta la gramática de identificadores y palabras clave. Las listas pueden cambiar según la versión; utiliza el módulo keyword del intérprete actual.

Nombres válidos como list o str pueden ocultar nombres incorporados. Prefiere otros que expresen la función del valor, como user_name o item_count. Ante NameError, revisa mayúsculas, asignación previa y ámbito donde el nombre está disponible.