Métodos en Python: instancia, clase y estáticos

Son los métodos más comunes en Python. Reciben automáticamente como primer argumento la instancia misma (self), lo que les permite acceder y modificar tanto atributos de instancia como de clase.

class Calculadora:
    factor = 10  # atributo de clase

    def __init__(self, base):
        self.base = base  # atributo de instancia

    def multiplicar(self, numero):
        resultado = self.base * numero * Calculadora.factor
        return resultado

Para invocarlos, es necesario crear una instancia previamente:

calc = Calculadora(5)
print(calc.multiplicar(3))  # 150
print(Calculadora.multiplicar(calc, 3))  # 150 (forma explícita)

Un método estático es una función definida dentro del cuerpo de una clase, pero que no recibe self ni cls automáticamente. Se comporta como una función ordinaria que simplemente reside en el espacio de nombres de la clase. No puede acceder a atributos de instancia ni de clase de forma directa.

Se puede definir mediante la función incorporada staticmethod() o, preferentemente, con el decorador @staticmethod.

class Utilidad:
    descripcion = "Clase de utilidad"

    def __init__(self):
        self.nombre = "Instancia de utilidad"

    @staticmethod
    def saludar(mensaje):
        return f"Mensaje: {mensaje}"

El método puede llamarse tanto desde la clase como desde una instanica, sin diferencia alguna:

print(Utilidad.saludar("Hola"))        # Mensaje: Hola
u = Utilidad()
print(u.saludar("Hola desde instancia"))  # Mensaje: Hola desde instancia

Como se observa, no existe acceso a descripcion ni a nombre dentro del método estático, pues no dispone de referencias automáticas a la clase ni a la instancia.

Los métodos de clase reciben como primer argumento la clase misma (cls), en lugar de una instancia. Esto les permite acceder y modificar atributos de clase, pero no atributos de instancia. Son útiles cuando se necesita lógica relacionada con la clase en general: contadores de instancias, factories, gestión de estado compartido, entre otros.

class Contador:
    total = 0

    def __init__(self, etiqueta):
        self.etiqueta = etiqueta
        Contador.total += 1

    @classmethod
    def obtener_total(cls):
        return f"Instancias creadas: {cls.total}"

Al consultar el método, siempre se opera sobre la clase, sin importar si se invoca desde la instancia:

c1 = Contador("primero")
c2 = Contador("segundo")
print(c1.obtener_total())   # Instancias creadas: 2
print(Contador.obtener_total())  # Instancias creadas: 2

Si se crea una subclase, cls hará referencia a la subclase, lo cual los hace especialmente útiles para patrones como el factory method.

El siguiente ejemplo reúne los tres tipos en una sola clase para apreciar sus diferencias:

class Demo:
    valor_clase = 100

    def __init__(self, valor_instancia):
        self.valor_instancia = valor_instancia

    # Método de instancia
    def metodo_instancia(self, x):
        self.valor_instancia = x
        return f"Instancia actualizada a {self.valor_instancia}"

    # Método estático
    @staticmethod
    def metodo_estatico(x):
        return f"Operación estática con {x}"

    # Método de clase
    @classmethod
    def metodo_clase(cls, x):
        return f"Clase: {cls.__name__}, valor_clase: {cls.valor_clase}, parámetro: {x}"

Formas de invocación:

d = Demo(10)

print(d.metodo_instancia(20))       # Instancia actualizada a 20
print(Demo.metodo_instancia(d, 20)) # Instancia actualizada a 20

print(d.metodo_estatico(5))         # Operación estática con 5
print(Demo.metodo_estatico(5))      # Operación estática con 5

print(d.metodo_clase(7))            # Clase: Demo, valor_clase: 100, parámetro: 7
print(Demo.metodo_clase(7))         # Clase: Demo, valor_clase: 100, parámetro: 7

Un detalle importante: al modificar valor_clase directamente en la clase, el método de clase refeljará el cambio. En cambio, si se asigna un atributo con el mismo nombre en una instancia, cls.valor_clase seguirá leyendo el valor del atributo de clase:

d.valor_clase = 999
print(d.metodo_clase(0))  # valor_clase sigue siendo 100

Demo.valor_clase = 999
print(d.metodo_clase(0))  # ahora valor_clase es 999

Etiquetas: Python oop classmethod staticmethod instance-method

Publicado el 7-30 11:01