Aprende leyendo en orden

Variables de clase vs variables de instancia — Dónde viven realmente los valores

Un recorrido con muchos diagramas por las variables de clase vs las variables de instancia en Python. Mira qué se comparte, qué es por instancia y qué hace realmente self.x = ....

La última vez terminamos con el uso práctico de __init__ —argumentos requeridos, argumentos por defecto— y conocimos el correspondiente __del__. Esta vez profundizaremos en los dos tipos de variables en una clase —variables de clase y variables de instancia— y veremos qué hace realmente self.x = ... a nivel de memoria.

Dos tipos de variables

Las variables que escribes en una clase de Python se dividen en dos tipos principales:

- Variables de clase: escritas directamente bajo class Product:. Compartidas por todas las instancias.

- Variables de instancia: escritas como self.x = ... dentro de un método. Propiedad de cada instancia individualmente.

Ambas se leen con la misma sintaxis de punto apple.name, así que no puedes distinguirlas a simple vista. Por eso mismo necesitas ser deliberado sobre "dónde vive realmente el valor".

class Product:
    tax_rate = 0.1                 # variable de clase (compartida por todos)

    def __init__(self, name):
        self.name = name           # variable de instancia (por instancia)

apple  = Product("apple")
banana = Product("banana")
Dónde viven realmente los valores
Productcuerpo de clasetax_rate=0.1(var de clase)applename='apple'banananame='banana'contienelookup compartidolookup compartido
La variable de clase tax_rate vive en un solo lugar en Product: tanto apple como banana miran el mismo punto. La variable de instancia name se almacena en la propia memoria de cada instancia.

Variables de clase — Un valor compartido por todos

Escribe una variable de clase directamente bajo class Product:, como tax_rate = 0.1. La parte clave es que vive fuera de cualquier método. La propia clase posee una copia, y cada instancia construida a partir de esa clase la comparte.

Puedes leerla como Product.tax_rate (vía la clase) o apple.tax_rate (vía una instancia). Para esta última, Python hace la búsqueda en este orden: primero comprueba la instancia, luego recurre a la clase.

Rango de búsqueda — Instancia primero, luego clase
Product (espacio de variables de clase)
  • tax_rate = 0.1 ← variable de clase (compartida)
apple (espacio de variables de instancia)
  • name = 'apple' ← variable de instancia
banana (espacio de variables de instancia)
  • name = 'banana' ← variable de instancia
Python busca un atributo comprobando primero la instancia y luego recurriendo a la clase exterior. Desde la perspectiva de la instancia, la variable de clase actúa como un paraguas compartido sobre ella.
class Product:
    tax_rate = 0.1                 # variable de clase (compartida por todos)

    def __init__(self, name, price):
        self.name = name           # variable de instancia (por instancia)
        self.price = price

apple = Product("apple", 150)
banana = Product("banana", 80)

print(Product.tax_rate)   # 0.1 (vía la clase)
print(apple.tax_rate)     # 0.1 (también legible a través de una instancia)
print(banana.tax_rate)    # 0.1

# Misma ubicación de memoria
print(id(apple.tax_rate) == id(Product.tax_rate))  # True

Añade una variable de clase y confirma que puedes leerla tanto desde la clase como desde las instancias.

① En class Product:, añade una variable de clase currency = "USD" en su propia línea (sobre __init__).

② Escribe __init__(self, name, price) que establece self.name = name y self.price = price.

③ Construye apple = Product("apple", 150). Ejecuta tanto print(Product.currency) como print(apple.currency) y confirma que muestran el mismo valor.

(Si lo ejecutas correctamente, aparecerá una explicación.)

Editor Python

Ejecutar el código para ver el resultado

Variables de instancia — Propiedad de cada instancia

Una variable de instancia se crea en el momento en que escribes self.x = ... dentro de un método, como un atributo exclusivo de esa instancia. Lo más habitual es inicializarlas en __init__ con algo como self.name = name, pero escribir self.x = ... en cualquier otro método también crea una nueva variable de instancia en ese momento.

Porque cada instancia almacena las variables de instancia en su propia memoria, cambiar apple.name no tiene efecto alguno sobre banana.name.

Cada instancia posee sus propias variables de instancia
apple(instancia)name = 'apple'(memoria separada)banana(instancia)name = 'banana'(memoria separada)contienecontiene
apple.name y banana.name viven en ubicaciones de memoria diferentes. Reescribir apple.name no afecta en absoluto a banana.name.
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

apple = Product("apple", 150)
banana = Product("banana", 80)

print(apple.name, apple.price)     # apple 150
print(banana.name, banana.price)   # banana 80

# id() muestra que apuntan a lugares diferentes
print(id(apple.name) == id(banana.name))   # False

Usa id() para sentir que las variables de instancia son verdaderamente separadas.

① Define class Product: con __init__(self, name, price) que establece self.name y self.price.

② Construye apple = Product("apple", 150) y banana = Product("banana", 80).

③ Ejecuta print(apple is banana) y print(id(apple.name) == id(banana.name)) y confirma que ambos son False.

Editor Python

Ejecutar el código para ver el resultado

self.x = ... crea una variable de instancia

Supongamos que Product tiene una variable de clase tax_rate = 0.1, y escribes apple.tax_rate = 0.05 para una instancia específica: ¿qué ocurre?

La respuesta: la variable de clase no se toca, y se crea una nueva variable de instancia tax_rate en apple. A partir de ese momento, apple.tax_rate devuelve 0.05 porque Python la encuentra primero en la instancia y nunca recurre a la clase. banana no se ve afectada en absoluto.

class Product:
    tax_rate = 0.1

    def __init__(self, name, price):
        self.name = name
        self.price = price

apple = Product("apple", 150)
banana = Product("banana", 80)

# Dar a apple solo una nueva tasa de impuesto
apple.tax_rate = 0.05

print(apple.tax_rate)      # 0.05 (variable de instancia de apple)
print(banana.tax_rate)     # 0.1  (recurre a la variable de clase)
print(Product.tax_rate)    # 0.1  (variable de clase sin cambios)
Qué cambia antes vs después de la asignación
apple(sin var instancia)banana(sin var instancia)Producttax_rate=0.1apple.tax_rate=0.05★ nuevatax_rate=0.05var instancia de applebanana(sin var instancia)Producttax_rate=0.1(sin cambios)lookup compartidolookuplookup
Fila superior (antes): tanto apple como banana comparten una búsqueda de tax_rate=0.1 en la clase. Fila inferior (después de apple.tax_rate = 0.05): nace una nueva variable de instancia en apple, y solo apple lee de ella. banana y la clase no se tocan.

No confundas esto con "actualizar una variable de clase a través de una instancia"

apple.tax_rate = 0.05 parece a primera vista "actualizar la variable de clase", pero en realidad solo crea una nueva variable de instancia en apple. Para cambiar la propia variable de clase compartida, necesitas asignar a través de la clase: Product.tax_rate = 0.05.

Confirma de forma práctica que self.x = ... crea una nueva variable de instancia.

① Define class Product: con la variable de clase tax_rate = 0.1 y __init__(self, name) que establece self.name = name.

② Construye apple = Product("apple") y banana = Product("banana").

③ Después de apple.tax_rate = 0.05, ejecuta print(apple.tax_rate), print(banana.tax_rate) y print(Product.tax_rate). Confirma que solo apple muestra el nuevo valor mientras los demás permanecen en 0.1.

Editor Python

Ejecutar el código para ver el resultado

Cuando quieres actualizar una variable de clase

Cuando necesitas actualizar el estado que la clase mantiene para todos —como "cambiar la tasa de impuesto para todas las instancias a la vez" o "llevar la cuenta acumulada de productos creados"— asignas a través de la variable de clase.

A continuación, Product.created_count vive en la propia clase y representa "el número de productos creados hasta ahora". Escribir Product.created_count += 1 dentro de __init__ actualiza el mismo único punto sin importar qué instancia se esté creando, así que el total acumulado se mantiene correcto. Si en su lugar escribieras self.created_count += 1, cada instancia obtendría su propia variable, derrotando el propósito original de contar.

Product.x += 1 vs self.x += 1
Product.x+= 1x de clase crecehasta 3total acumuladofuncionaself.x+= 1cada instanciacrea una nueva xx de clase quedaen 0actualizarresultadoasignarresultado
Asignar a través de la clase permite que todos incrementen el mismo único contador. Con self.x += 1, cada instancia acaba con su propia copia, y el contador compartido se queda en 0.
class Product:
    created_count = 0          # variable de clase: cuenta acumulada de productos

    def __init__(self, name):
        self.name = name
        Product.created_count += 1   # actualizar a través de la clase

apple = Product("apple")
banana = Product("banana")
orange = Product("orange")

print(Product.created_count)  # 3
print(apple.created_count)    # 3 (también legible vía una instancia)

Construye un contador que incremente una variable de clase en 1 cada vez que se crea una instancia.

① En class Product:, añade una variable de clase created_count = 0.

② En __init__(self, name), después de self.name = name, escribe Product.created_count += 1 en una sola línea.

③ Crea Product("apple"), Product("banana") y Product("orange") por turno, luego ejecuta print(Product.created_count) y confirma que muestra 3.

Editor Python

Ejecutar el código para ver el resultado

Aclaramos los dos tipos de variables en una clase, confirmamos que self.x = ... siempre crea una nueva variable de instancia, que las variables de instancia ocultan a las variables de clase cuando están presentes, y que el estado compartido se actualiza a través de la clase.

QUIZ

Verificación de conocimientos

Responde cada pregunta una a una.

Pregunta 1¿Dónde escribes una variable de clase?

Pregunta 2¿Qué imprime el print final?
class P:
n = 10
a = P()
a.n = 99
b = P()
print(b.n)

Pregunta 3Para contar la variable de clase count entre todas las instancias, ¿qué deberías escribir dentro de __init__?