Skip to content

Python de Cero a Pro - Cap. 13 - Static & Class Methods

Python de Cero a Pro - Cap. 13 - Métodos de Clase y Estáticos

Volver a Página Principal

Ver Codigo en GitLab

Python de Cero a Pro - Cap. 13: Métodos Especiales 🚀

Section titled “Python de Cero a Pro - Cap. 13: Métodos Especiales 🚀”

¡Bienvenidos al Capítulo 13! Tras haber construido nuestra base de CLI en el capítulo anterior, hoy daremos un salto de calidad profesional. Aprenderemos a usar los decoradores @classmethod y @staticmethod, herramientas esenciales para organizar lógica que pertenece a la clase pero no necesariamente a una instancia (objeto) específica. 🛠️

¿Qué aprenderemos hoy?

  1. @classmethod: Métodos que reciben la clase (cls) como primer argumento. Ideales para factorías o consultas globales.
  2. @staticmethod: Métodos que no necesitan acceso ni a la instancia (self) ni a la clase (cls). Son funciones de utilidad dentro del espacio de nombres de la clase.
  3. Persistencia Pro: Cómo consultar datos de un archivo JSON sin necesidad de crear un objeto nuevo cada vez.

Un decorador en Python es una función que recibe otra función como argumento y devuelve una nueva función que extiende o modifica el comportamiento de la original, sin alterar su código fuente. Este patrón permite añadir funcionalidades comunes —como registro (logging), autenticación, validación o medición de tiempo— de forma elegante y reutilizable.

La sintaxis @nombre_decorador se conoce como syntactic sugar y es equivalente a asignar la función decorada explícitamente, por ejemplo: funcion_decorada = nombre_decorador(funcion_original).

  • Extiende comportamiento: Añade código antes, después o alrededor de la función decorada.
  • Reutilizable: Puede aplicarse a múltiples funciones sin repetir código.
  • Mantiene la originalidad: La función original permanece intacta; solo se envuelve con nueva funcionalidad.
  • Soporta argumentos: Se pueden crear decoradores parametrizados mediante funciones anidadas.

Ejemplo básico:

def mi_decorador(func):
def wrapper():
print("Algo antes de la función")
func()
print("Algo después de la función")
return wrapper
@mi_decorador
def saludar():
print("¡Hola!")
saludar()
# Salida:
# Algo antes de la función
# ¡Hola!
# Algo después de la función

Profundizando: ¿Por qué son vitales para el Desarrollo Estándar?

Section titled “Profundizando: ¿Por qué son vitales para el Desarrollo Estándar?”

En el desarrollo de software moderno, no basta con que el código resuelva el problema; debe ser mantenible y predecible. Estos decoradores son pilares del Clean Code:

  • Encapsulamiento y Semántica: Al usar @classmethod, le indicamos a otros desarrolladores que la operación es de nivel “Entidad” (como buscar en una DB). Con @staticmethod, aclaramos que es una herramienta de apoyo que no alterará el estado del objeto.
  • Eficiencia de Memoria: No necesitamos instanciar un objeto (Usuarios()) para realizar tareas de utilidad o consultas, ahorrando recursos del sistema.
  • Estandarización: En proyectos grandes (como integraciones de ERP o CRM), centralizar la lógica de búsqueda en métodos de clase evita que cada desarrollador cree su propia forma de leer archivos, manteniendo el proyecto bajo un mismo estándar.

Se usa cuando el método necesita conocer la clase en la que se está ejecutando (por ejemplo, para acceder a atributos de clase como la ruta de un archivo).

  • Uso común: “Factory methods” (crear objetos desde un dict) o métodos de búsqueda global.

Se usa cuando el método es puramente lógico y no depende del estado de ningún objeto ni de la clase.

  • Uso común: Validaciones de formato (email, fechas), limpieza de strings o cálculos matemáticos.

Práctica: Mejorando el Modelo de Usuarios

Section titled “Práctica: Mejorando el Modelo de Usuarios”

Vamos a aplicar estos conceptos a nuestro archivo models/usuarios.py para permitir la consulta de datos persistentes y validaciones limpias.

models/usuarios.py
from modules.save_json import save_json, load_json, find_in_json
class Usuarios:
# Atributos de clase (compartidos por todas las instancias)
path = "data/users/"
filename = "users.json"
def __init__(self, nombre=None, email=None):
self.name = nombre
self.email = email
@classmethod
def obtener_todos(cls):
"""
Consulta global: No requiere instanciar Usuarios()
Usa 'cls' para acceder a cls.filename y cls.path de forma estándar.
"""
print(f"--- Cargando datos desde {cls.filename} ---")
return load_json(cls.filename, cls.path)
@classmethod
def buscar_por_nombre(cls, nombre):
"""Busca un usuario específico en el JSON sin crear una instancia previa"""
return find_in_json("name", nombre, cls.filename, cls.path)
@staticmethod
def validar_email(email):
"""
Desarrollo Limpio: Lógica pura de validación.
No depende de 'self' ni de 'cls'.
"""
return "@" in email and "." in email
def registrar(self, nombre, email):
if not self.validar_email(email):
print("Error: Email inválido.")
return False
data = {
"name": nombre,
"email": email
}
save_json(data, self.filename, self.path)
print(f"Usuario {nombre} guardado exitosamente.")

Gracias a estos métodos, nuestro menú de consultas es mucho más limpio:

# Ejemplo de uso en el menú de consultas
elif opcion == '4':
# ¡Llamada estandarizada! No usamos Usuarios() con paréntesis.
lista = Usuarios.obtener_todos()
for u in lista:
print(f"Nombre: {u['name']} | Email: {u['email']}")

Al incorporar @classmethod y @staticmethod, tu código deja de ser un simple script y se convierte en una arquitectura escalable. Esto es fundamental cuando trabajas en proyectos complejos, donde necesitas métodos de consulta rápidos, limpios y fáciles de testear.

En el próximo capítulo, exploraremos la Herencia, para evitar repetir código entre Productos, Usuarios y Ventas. ¡Sigue programando! 💪📚