Pregunta 1¿Qué decorador usas para definir un método estático?
Métodos de instancia, de clase y estáticos — Los tres tipos de métodos
Aprende los tres tipos de métodos de Python —de instancia, de clase y estáticos— con diagramas. Recorre el uso de self / cls / sin primer argumento y cuándo elegir cada uno.
La última vez cubrimos la diferencia entre las variables de clase y las de instancia. Cada método que hemos escrito hasta ahora en la forma def method(self, ...) es un método de instancia, pero las clases de Python tienen dos tipos más: métodos de clase y métodos estáticos. Esta vez aclararemos los tres tipos y cómo elegir entre ellos.
Hay tres tipos de métodos
Los métodos de una clase de Python se dividen en tres tipos, distinguidos por lo que toman como su primer argumento:
- Método de instancia: primer parámetro self. Recibe la propia instancia.
- Método de clase: primer parámetro cls. Recibe la propia clase. Decorado con @classmethod.
- Método estático: sin primer parámetro. No toma ni self ni cls. Decorado con @staticmethod.
El tipo determina a qué puede acceder cada método. Solo los métodos de instancia pueden tocar las variables de instancia self.x. Los métodos de clase son la forma de trabajar con variables de clase desde el lado de la clase, y los métodos estáticos son para lógica pura que no toca ninguna de las dos.
Métodos de instancia — Tomando self
La forma def method(self, ...) que has estado escribiendo todo el tiempo es un método de instancia. El primer parámetro self se rellena automáticamente con la instancia desde la que se llamó al método, así que puedes acceder a las variables de instancia como self.name.
Cuando escribes apple.show(), Python lo traduce internamente a Product.show(apple). Puedes pensar en los métodos como "funciones que toman una instancia como su primer argumento".
class Product:
def __init__(self, name, price):
self.name = name
self.price = price
def total_with_tax(self, tax_rate): # método de instancia
return int(self.price * (1 + tax_rate))
apple = Product("apple", 150)
print(apple.total_with_tax(0.1)) # 165
# Internamente igual que esto
print(Product.total_with_tax(apple, 0.1)) # 165
__init__ establece apple.price = 150 → ② llamar a apple.method(0.1) pone apple en self → ③ self.price lee el valor establecido en la instancia.Métodos de clase — @classmethod y cls
Un método de clase se define con el decorador @classmethod, con cls como primer parámetro (un nombre convencional). cls contiene automáticamente la propia clase: en este caso el plano Product.
Usa los métodos de clase cuando quieras leer o escribir una variable de clase o construir y devolver una única instancia (un factory). También puedes llamarlos a través de una instancia (apple.method()), pero llamarlos en la clase como Product.method() es lo estándar.
class Product:
total_count = 0 # variable de clase
def __init__(self, name, price):
self.name = name
self.price = price
Product.total_count += 1
@classmethod # ① devuelve una variable de clase
def get_total(cls):
return f"{cls.total_count} productos registrados"
@classmethod # ② construye y devuelve una instancia (factory)
def from_csv_row(cls, row):
name, price = row.split(",")
return cls(name, int(price))
Product("apple", 150)
Product("banana", 80)
print(Product.get_total()) # 2 productos registrados
orange = Product.from_csv_row("orange,120")
print(orange.name, orange.price) # orange 120
get_total(cls) (decorado con @classmethod) como Product.get_total() pone automáticamente la propia clase Product en cls. Desde ahí puedes acceder a las variables de clase como cls.total_count.def total_with_tax(self, tax_rate):- Llamada:
apple.total_with_tax(0.1) - →
selfse convierte enapple - Accede a la variable de instancia self.price
- Decorado con
@classmethod def get_total(cls):- Llamada:
Product.get_total()(desde la clase) - →
clsse convierte enProduct - Accede a la variable de clase cls.total_count
Métodos estáticos — @staticmethod
Un método estático se define con @staticmethod y no toma ni self ni cls. Es "una función simple que vive en la clase": completa su trabajo usando solo sus argumentos, sin acceso a variables de instancia o de clase.
Encaja en casos donde el trabajo está relacionado con la clase pero no depende de una instancia o estado de clase concretos: validación de entrada, formateo, cálculos puros usando constantes. Úsalo para mantener funciones de utilidad junto a la clase relacionada en lugar de escribirlas como funciones independientes.
class Product:
def __init__(self, name, price):
if not Product.is_valid_price(price):
raise ValueError(f"precio inválido: {price}")
self.name = name
self.price = price
@staticmethod
def is_valid_price(price): # sin self, sin cls
return 0 <= price <= 1_000_000
print(Product.is_valid_price(150)) # True
print(Product.is_valid_price(-1)) # False
# Product("apple", -1) # ValueError: precio inválido: -1
Los métodos estáticos funcionan desde la clase o desde la instancia
Tanto Product.is_valid_price(150) como apple.is_valid_price(150) funcionan igual. Pero como el método en realidad no usa la instancia, llamarlo en la clase hace la intención más clara. Escribir apple.is_valid_price(...) hace que un lector se detenga y se pregunte "¿depende esto del estado de apple?": mejor evitarlo.
Eligiendo entre los tres
Cuál usar se puede decidir mecánicamente basándose en "a qué necesita acceder el método".
- Toca variables de instancia (self.x) → método de instancia
- Solo toca variables de clase (cls.x) → método de clase
- No toca ninguna (solo impulsado por argumentos) → método estático
En caso de duda: primero comprueba si tocas variables de instancia. Si no, comprueba las variables de clase. Si ninguna, estático. Ese orden no te llevará por mal camino.
self.x? Siguiente: ¿manejas variables de clase? Si ninguna, estático es la elección correcta.| Tipo | Decorador | 1er parámetro | Uso típico |
|---|---|---|---|
| Método de instancia | ninguno | self | Métodos regulares que leen/escriben self.x |
| Método de clase | @classmethod | cls | Leer/escribir variables de clase, factories |
| Método estático | @staticmethod | ninguno | Validación, formateo, lógica pura |
Con este artículo has cubierto los tres tipos de métodos —instancia / clase / estático— y cómo elegir entre ellos. Eso completa el conjunto básico de clases, instancias, atributos y métodos en Python. Desde aquí, puedes pasar a los tres pilares de la programación orientada a objetos: encapsulación (controlar la visibilidad de los atributos), herencia (heredar capacidades de otra clase) y polimorfismo (el mismo nombre de método comportándose de forma diferente según el tipo).
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2¿Qué método es el más natural para @classmethod?
Pregunta 3¿Qué métodos se pueden llamar sin crear una instancia? (Elige la única respuesta más apropiada si se aplican varias.)