Pregunta 1¿Dónde escribes una variable de clase?
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")
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.
- tax_rate = 0.1 ← variable de clase (compartida)
- name = 'apple' ← variable de instancia
- name = 'banana' ← variable de instancia
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
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.
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
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)
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.
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.
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)
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.
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2¿Qué imprime el print final?class P: n = 10a = P()a.n = 99b = P()print(b.n)
Pregunta 3Para contar la variable de clase count entre todas las instancias, ¿qué deberías escribir dentro de __init__?