Regístrate para acceder a más de 15 cursos gratuitos de programación con un simulador

Enlace estático tardío Python: Profundizando en las clases

En esta lección vamos a de los métodos estáticos (@staticmethod), los métodos de clase (@classmethod) y los atributos de clase.

Aunque estos conceptos pueden parecer similares, en realidad cumplen roles diferentes. Juntos, vamos a entender cómo funcionan, por qué son útiles y cómo usarlos correctamente, sobre todo cuando trabajamos con herencia entre clases.


¿Qué es un método estático?

El método estático es como una función normal, pero vive dentro de una clase. No necesita que haya un objeto (una instancia) creado para poder usarse. Para definirlo usamos el decorador @staticmethod.
class A:
    @staticmethod
    def saludo():
        print("Hola desde A")

A.saludo()  # 'Hola desde A'

Como puedes ver, no necesitamos crear un objeto de A. Llamamos el método directamente desde el nombre de la clase.

Ahora, veamos un ejemplo un poco más interesante con herencia:

class A:
    @staticmethod
    def quien():
        print('A')

    @staticmethod
    def prueba():
        A.quien()

class B(A):
    @staticmethod
    def quien():
        print('B')

B.prueba()  # 'A'

Aunque B hereda de A y redefine el método quien(), el método prueba() llama a A.quien(), no a B.quien(). Esto pasa porque al ser un método estático, no tiene conocimiento del contexto del objeto o clase desde donde se está llamando. Se ejecuta exactamente tal como está escrito, lo cual puede ser una limitación con la herencia.

💡 Si necesitas que el método sepa qué clase lo está llamando, mejor usa un método de clase.

Atributos de clase

Los atributos de clase son valores que se guardan en el nivel del clase, no del objeto. Esto quiere decir que todos los objetos de esa clase comparten ese mismo valor.

Un caso práctico muy común: imaginemos que estamos trabajando con una base de datos. Cada modelo representa una tabla.

class Usuario:
    _tabla = 'usuarios'

Este atributo _tabla es importante para saber en qué tabla se debe guardar un objeto Usuario. Como esta información es compartida por todos los usuarios, no tiene sentido guardarla en cada objeto. Por eso, lo hacemos como atributo de clase.

Ahora, queremos crear una clase base que pueda manejar la lógica común para varios modelos:

class EntidadBase:
    pass

class Usuario(EntidadBase):
    _tabla = 'usuarios'

❓ ¿Y si ahora queremos acceder al nombre de tabla desde el método de EntidadBase?

Vamos a intentarlo.

class EntidadBase:
    def obtener_tabla():
        return _tabla  # Esto da error

print(Usuario.obtener_tabla())  # NameError

Esto no funciona porque _tabla no está definido dentro de EntidadBase. Pero sí está en Usuario, y podemos resolver esto fácilmente usando un método de clase.


Métodos de clase y acceso a atributos heredados

Un método de clase se define usando el decorador @classmethod. A diferencia del método estático, el método de clase recibe como primer argumento a la clase en sí (con la palabra cls, por convención).

Así podemos acceder no solo a atributos definidos en la clase base, sino también a los que definen las subclases.

class EntidadBase:
    @classmethod
    def obtener_tabla(cls):
        return cls._tabla

class Usuario(EntidadBase):
    _tabla = 'usuarios'

print(Usuario.obtener_tabla())  # 'usuarios'

Fíjate que el método obtener_tabla se define en EntidadBase, pero cuando lo llamamos desde Usuario, accede al atributo _tabla definido en Usuario. Eso es porque cls representa la clase desde donde se llama el método, no necesariamente donde se definió.

Este comportamiento es muy útil cuando estamos diseñando jerarquías de clases en donde cada subclase puede tener sus propios valores.

Comparación rápida

Elemento Decorador Primer argumento ¿Accede a instancia? ¿Accede a clase? Útil para...
Método normal (ninguno) self No Acciones que dependen de datos del objeto
Método de clase @classmethod cls No Lógica relacionada a la clase o herencia
Método estático @staticmethod ninguno No No Funciones utilitarias dentro de la clase

Caso práctico con herencia

Imaginemos que tenemos un sistema de almacenamiento donde varias entidades se guardan en tablas distintas. Podemos crear una clase base que contenga la lógica común de guardado y que acceda a la tabla correcta según la clase que se esté usando.

class EntidadBase:
    @classmethod
    def guardar(cls, datos):
        print(f"Guardando en tabla '{cls._tabla}': {datos}")

class Usuario(EntidadBase):
    _tabla = 'usuarios'

class Producto(EntidadBase):
    _tabla = 'productos'

Usuario.guardar({'nombre': 'Laura'})   # Guardando en tabla 'usuarios': {'nombre': 'Laura'}
Producto.guardar({'nombre': 'Sombrero'})  # Guardando en tabla 'productos': {'nombre': 'Sombrero'}

Gracias a @classmethod y el uso de cls._tabla, podemos reutilizar guardar() sin duplicar el código en cada clase hija. Y cada clase puede tener su propia tabla.


Resumen

  • Los métodos estáticos (@staticmethod) no conocen ni el objeto (self) ni la clase (cls). Son como funciones normales pero agrupadas dentro de una clase.
  • Los métodos de clase (@classmethod) reciben la clase como primer argumento (cls) y permiten acceder a atributos del propio tipo, incluso si fueron definidos en una subclase.
  • Los atributos de clase son valores compartidos por todos los objetos de esa clase. No dependen del estado de un objeto específico.
  • Para trabajar bien con herencia y lógica común entre entidades, es mejor usar métodos de clase en lugar de métodos estáticos.
  • Usar cls en lugar de referirnos directamente al nombre del padre (A, EntidadBase, etc.) nos permite respetar la jerarquía de herencia y mantener flexibilidad.

Para acceder completo a curso necesitas un plan básico

El plan básico te dará acceso completo a todos los cursos, ejercicios y lecciones de Códica, proyectos y acceso de por vida a la teoría de las lecciones completadas. La suscripción se puede cancelar en cualquier momento.

Obtener acceso
130
cursos
1000
ejercicios
2000+
horas de teoría
3200
test

Obtén acceso

Cursos de programación para principiantes y desarrolladores experimentados. Comienza tu aprendizaje de forma gratuita

  • 130 cursos, 2000+ horas de teoría
  • 1000 ejercicios prácticos en el navegador
  • 360 000 estudiantes
Al enviar el formulario, aceptas el «Política de privacidad» y los términos de la «Oferta», y también aceptas los «Términos y condiciones de uso»

Nuestros graduados trabajan en empresas como:

Bookmate
Health Samurai
Dualboot
ABBYY