Decoradores en Python: Extiende Funcionalidades de Funciones
Resumen
Cuando trabajas en un entorno profesional con Python, es muy común necesitar añadir comportamientos antes o después de una función sin alterar su lógica interna. Los decoradores son la herramienta que permite lograr exactamente eso: extender la funcionalidad de una función manteniéndola intacta por dentro. A continuación se explica cómo funcionan, cuál es su estructura y cómo aplicarlos en casos prácticos.
¿Qué es un decorador y cuál es su estructura?
Un decorador en Python es una función que recibe otra función como parámetro, le añade comportamiento adicional y retorna una nueva función modificada. La sintaxis se apoya en el uso del símbolo @ seguido del nombre del decorador, colocado justo encima de la función que se desea extender [0:28].
La estructura general sigue este patrón:
Se define una función decoradora que recibe como argumento la función original.
Dentro de ella se crea una función interna, comúnmente llamada wrapper (envolvedor), que contiene el nuevo comportamiento.
Se ejecuta la función original dentro del wrapper.
El decorador retorna la función wrapper.
Este concepto de wrapper es fundamental: su rol es envolver la función original con las instrucciones adicionales que necesites, ya sea registrar logs, validar permisos o cualquier otra lógica.
¿Cómo implementar un decorador paso a paso?
El primer ejemplo práctico consiste en crear un decorador que registre un log antes y después de procesar un pago [2:06]. La función base es muy sencilla:
python
def registrar_log(funcion):
def wrapper():
print("Log de la transacción iniciando...")
funcion()
print("Log terminado...")
return wrapper
Al llamar procesar_pago(), el resultado sigue tres pasos en orden:
Se imprime "Log de la transacción iniciando...".
Se ejecuta "Procesando pago...".
Se imprime "Log terminado...".
Fíjate que la función procesar_pago no fue modificada internamente. Todo el comportamiento extra vive en el decorador, lo que permite reutilizarlo en otras funciones.
¿Cómo usar decoradores con parámetros en la función original?
El segundo ejemplo añade complejidad real: un decorador que verifica si un empleado tiene rol de administrador antes de permitirle eliminar a otro empleado [5:15]. La función base recibe un diccionario con información del empleado:
python
@verificar_rol
def eliminar_empleado(empleado):
print(f"El empleado {empleado['nombre']} ha sido eliminado")
El decorador valida el rol antes de ejecutar la acción:
python
def verificar_rol(funcion):
def wrapper(empleado):
if empleado["rol"] == "admin":
return funcion(empleado)
else:
print("Acceso denegado. Solo los administradores pueden acceder.")
return wrapper
Cuando el wrapper recibe el parámetro empleado, comprueba la clave rol del diccionario. Si el valor es "admin", se ejecuta la función original. En caso contrario, se deniega el acceso con un mensaje claro.
Al llamar eliminar_empleado(admin), el resultado es: "El empleado Carlos ha sido eliminado". Al llamar eliminar_empleado(empleado), se obtiene: "Acceso denegado. Solo los administradores pueden acceder" [9:12].
Un detalle importante que surgió durante la implementación fue un error de inconsistencia en los nombres de las llaves del diccionario. La clave definida como "rol" debe coincidir exactamente con la que se consulta en el decorador. Este tipo de bug es frecuente cuando se mezclan idiomas en las claves.
¿Por qué los decoradores son tan útiles en proyectos reales?
Los decoradores permiten separar responsabilidades de forma limpia. En lugar de mezclar validaciones, logs o métricas dentro de cada función, se encapsulan en decoradores reutilizables. Esto significa que puedes:
Añadir registro de actividad a cualquier función con @registrar_log.
Controlar acceso basado en roles con @verificar_rol.
Decidir cuándo ejecutar o bloquear una función sin tocar su código.
El reto propuesto consiste en crear un decorador que registre cada acción de un empleado en un archivo de texto, combinando lo aprendido sobre decoradores con manejo de archivos.
¿Qué otros decoradores se te ocurren para este sistema de gestión de empleados? Comparte tus ideas y soluciones en los comentarios.
Los decoradores en Python son funciones que modifican el comportamiento de otras funciones o métodos. Son una herramienta muy útil para añadir funcionalidades o preprocesamientos sin tener que cambiar el código original de la función decorada.
### ¿Qué es un Decorador?
Un decorador es una función que toma otra función como argumento y le añade funcionalidades adicionales. Devuelve una nueva función modificada o envuelta con el comportamiento adicional.
La sintaxis básica de un decorador utiliza el símbolo @ seguido del nombre del decorador antes de la definición de la función que se quiere decorar:
@mi\_decorador
deffuncion():  pass
### Ejemplo Básico de Decorador
Aquí tienes un ejemplo de un decorador que muestra un mensaje antes y después de ejecutar la función:
def mi\_decorador(funcion):  def wrapper():  print("Antes de la función")  funcion()  print("Después de la función")  return wrapper@mi\_decorador
defsaludo():  print("Hola")saludo()
**Salida:**
Antes de la función
Hola
Después de la función
### Decoradores con Argumentos en las Funciones
Si la función original toma argumentos, el decorador debe adaptarse para recibirlos y pasarlos correctamente:
def decorador\_con\_argumentos(funcion):  def wrapper(\*args, \*\*kwargs):  print("Llamando a la función con argumentos:", args, kwargs)  resultado = funcion(\*args, \*\*kwargs)  print("Resultado:", resultado)  return resultado  return wrapper@decorador\_con\_argumentos
defsuma(a, b):  return a + bsuma(3,5)
**Salida:**
Llamando a la función con argumentos: (3, 5) {}
Resultado: 8
### Decoradores Anidados
Se pueden aplicar varios decoradores a una misma función. En este caso, los decoradores se aplican en orden desde el más cercano a la función hacia el exterior:
Los decoradores no solo se limitan a funciones; también pueden aplicarse a clases para modificar su comportamiento. Aquí tienes un ejemplo de decorador que modifica el método \_\_init\_\_ de una clase:
def decorador\_clase(cls):  class NuevaClase(cls):  def \_\_init\_\_(self, \*args, \*\*kwargs):  print("Iniciando con decorador de clase")  super().\_\_init\_\_(\*args, \*\*kwargs)  return NuevaClase@decorador\_clase
classPersona:  def \_\_init\_\_(self, nombre):  self.nombre = nombrep = Persona("Carlos")
**Salida:**
Iniciando con decorador de clase
### Decoradores Integrados en Python
Python ofrece algunos decoradores integrados, como:
- @staticmethod: Define métodos estáticos que no requieren una instancia de la clase.
- @classmethod: Define métodos de clase que reciben la clase como primer argumento en lugar de la instancia.
- @property: Define métodos como propiedades, permitiendo acceso a métodos como si fueran atributos.
### Decoradores con Argumentos Propios
A veces, es útil que un decorador acepte argumentos. En estos casos, el decorador se define dentro de otra función, lo cual permite que la función exterior reciba argumentos:
Los decoradores son una herramienta poderosa en Python que permite modificar funciones y métodos sin cambiar su implementación interna, siendo útiles para casos como:
- Validación de datos
- Manejo de excepciones
- Medición de tiempo de ejecución
- Creación de APIs
Claps!!
MUY BUEN APORTE
from datetime import datetime
"""
Implementa un decorador llamado log_employee_action
que registre cualquier acción realizada por un empleado en un archivo de texto.
"""# Función decorador que será la de escribir en el archivo de texto las acciones de los empleadosdeflog_empleados(func):defwrapper(empleado):print('Log de la transaccion...')withopen('log.txt','a')asfile:file.write(f'{func(empleado)}\n')print('Log terminado...')return wrapper
# Función decorador que será la de escribir en el archivo de texto las acciones de los admin# La diferencia es la cantidad de parámetros, todos se registra en el mismo log.txtdeflog_admin(func):defwrapper(empleado, admin):print('Log de la transaccion...')withopen('log.txt','a')asfile:file.write(f'{func(empleado, admin)}\n')print('Log terminado...')return wrapper
# Función que permite al rol admin eliminar un empleado@log_admindefeliminar_empleado(empleado, admin):print(f"{datetime.now()} El administrador {admin['nombre']} ha eliminado al empleado {empleado['nombre']}")returnf"{datetime.now()} El administrador {admin['nombre']} ha eliminado al empleado {empleado['nombre']}"# Función que permite al rol admin registrar un empleado@log_admindefregistrar_empleado(empleado, admin):print(f"{datetime.now()} El administrador {admin['nombre']} ha registrado al empleado {empleado['nombre']}")returnf"{datetime.now()} El administrador {admin['nombre']} ha registrado al empleado {empleado['nombre']}"# Función que permite al rol empleado ingresar al sistema@log_empleadosdefingresar_al_sistema(empleado):print(f"{datetime.now()} El empleado {empleado['nombre']} ha ingresado al sistema")returnf"{datetime.now()} El empleado {empleado['nombre']} ha ingresado al sistema"# Función que permite al rol empleado salir del sistema@log_empleadosdefsalir_del_sistema(empleado):print(f"{datetime.now()} El empleado {empleado['nombre']} ha salido al sistema")returnf"{datetime.now()} El empleado {empleado['nombre']} ha salido del sistema"# Ejemplo de uso# Se crea un admin y 3 empleadosadmin ={'nombre':'Iris','rol':'admin'}e1 ={'nombre':'Jose','rol':'empleado'}e2 ={'nombre':'Ana','rol':'empleado'}e3 ={'nombre':'Samuel','rol':'empleado'}ingresar_al_sistema(e1)# José ingresa al sistemaingresar_al_sistema(e3)# Samuel ingresa al sistemasalir_del_sistema(e3)# Samuel sale del sistemaeliminar_empleado(e3, admin)# El admin Iris elimina al empleado Samuelregistrar_empleado(e2, admin)# El admin Iris registra al empleado Ana
Gracias por tu aporte!
Carli, explica muy bien el concepto; es claro a lo que se quiere trabajar, sin embargo, quiero añadir que me pareció ilógico un admin eliminándose a él mismo.
¿Qué hice?
Dentro del wrap le agregue dos argumentos: quién va a eliminar y quién será eliminado.
Justo comenté lo mismo, no hace sentido.
Creo que en el ejemplo mostrado hay un error en la lógica de permisos: el código actual solo permite eliminar usuarios que son admin, cuando la idea debería ser que un administrador pueda eliminar a otros usuarios. En realidad, el decorador debería verificar el rol del usuario que ejecuta la acción, no del usuario sobre el que se aplica.
Como realmente deberia haber sido el codigo para que tenga sentido:
def verificar_acceso(func): def wrapper(actor, objetivo,*args,**kwargs):if actor.get('role')=='admin': # Verificamos al que ejecuta
returnfunc(actor, objetivo,*args,**kwargs)else:print("Acceso denegado: solo un administrador puede eliminar empleados.")return wrapper
@verificar_acceso
def eliminar_empleado(actor, objetivo):print(f"El administrador {actor['nombre']} ha eliminado a {objetivo['nombre']}.")# Datosadmin ={"nombre":"Carlos","role":"admin"}empleado ={"nombre":"Ana","role":"empleado"}# Pruebaseliminar_empleado(admin, empleado) # ✅ debería funcionar
eliminar_empleado(empleado, admin) # ❌ acceso denegado
Los decoradores en Python son una herramienta poderosa y flexible que permite modificar o extender la funcionalidad de funciones o métodos sin cambiar su código original. Son funciones que "envuelven" otra función o método, lo que permite agregar comportamientos adicionales antes o después de la ejecución de la función original.
¿Cómo funcionan los decoradores?
Un decorador toma una función como entrada, la "envuelve" o "modifica", y luego devuelve una nueva función con la funcionalidad extendida o alterada. Los decoradores se aplican a las funciones usando el símbolo @ encima de la definición de la función.
Sintaxis básica de un decorador:
defdecorador(func):defenvoltura():print("Algo antes de la función original.") func()print("Algo después de la función original.")return envoltura
@decoradordefmi_funcion():print("Esta es la función original.")mi_funcion()```Explicación del ejemplo:* `decorador(func)`: El decorador toma una función `func` como parámetro.* `envoltura()`: Es una nueva función que envuelve a la función original. Dentro de esta función, puedes agregar código antes y después de llamar a la función original.* `return envoltura`: El decorador devuelve la función modificada.Cuando ejecutas `mi_funcion()`, el decorador "envuelve" la función y se ejecuta el código adicional alrededor de la función original.### Salida del código anterior:Algo antes de la función original.Esta es la función original.Algo después de la función original.### Ejemplo de un decorador con parámetros:A veces, los decoradores también pueden aceptar parámetros adicionales, permitiendo mayor flexibilidad.
```python
defdecorador_con_parametros(valor):defdecorador(func):defenvoltura(*args,**kwargs):print(f"Valor del decorador: {valor}")return func(*args,**kwargs)return envoltura
return decorador
@decorador_con_parametros("Hola Mundo")defsaludar():print("Saludos!")saludar()```Salida:Valor del decorador: Hola Mundo
Saludos!
### Aplicaciones de los decoradores:1.**Registro de actividades (logging)**: Puedes usar decoradores para hacer seguimiento de las funciones que se ejecutan, qué parámetros se pasan, y qué resultados devuelven.2.**Autenticación y autorización**: Puedes aplicar decoradores para verificar si un usuario tiene permiso para ejecutar ciertas funciones.3.**Medición de tiempo de ejecución (timing)**: Un decorador puede medir cuánto tiempo tarda en ejecutarse una función.4.**Cacheo o memoización**: Los decoradores también son útiles para almacenar en caché los resultados de una función para evitar cálculos repetidos.### Decoradores en Python con funciones estándar y clases:***Funciones estándar**: Como se mostró en los ejemplos anteriores.***Clases y métodos**: También se pueden usar decoradores con métodos dentro de clases, donde el decorador modifica el comportamiento de los métodos.### En resumen:Los decoradores son una forma de **modificar el comportamiento de una función o método** sin cambiar su código directamente. Son útiles para tareas comunes y repetitivas como el registro de actividades, la medición de tiempos, la verificación de permisos, y más.
Aquí está el reto de la clase, también agregué otros decoradores para seguir practicando un poco en el tema
import datetime
import functools
import time
deflog_employee_action(func):"""
Este decorador registra cualquier acción realizada por un empleado
en un archivo de texto llamado 'acciones_empleados.txt'.
"""@functools.wraps(func)defwrapper(nombre_empleado,*args,**kwargs):# 1. Obtener la fecha y hora actual ahora = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 2. Preparar el mensaje del registro mensaje =f"[{ahora}] El empleado '{nombre_empleado}' ejecutó la acción: '{func.__name__}'\n"# 3. Guardar el mensaje en el archivo (modo 'a' para añadir sin borrar)withopen("acciones_empleados.txt","a", encoding="utf-8")as archivo: archivo.write(mensaje)# 4. Ejecutar la función originalreturn func(nombre_empleado,*args,**kwargs)return wrapper
# --- Ejemplo de uso ---@log_employee_actiondefregistrar_entrada(nombre):print(f"Entrada registrada para: {nombre}")@log_employee_actiondefprocesar_venta(nombre, producto):print(f"{nombre} está procesando la venta de: {producto}")if __name__ =="__main__":# Probamos las funciones registrar_entrada("Ana Garcia") procesar_venta("Carlos Perez","Laptop Pro") procesar_venta("Ana Garcia","Laptop Pro")print("\nAcciones registradas en 'acciones_empleados.txt'.")defmedir_tiempo(function):defenvolver(*args,**kwargs): inicio = time.time() resultado = function(*args,**kwargs) fin = time.time()print(f"La acción tomó {fin - inicio:.2f} segundos.")return resultado
return envolver
@medir_tiempodefprocesar_venta(nombre, producto):print(f"{nombre} está procesando la venta de: {producto}")if __name__ =="__main__": procesar_venta("Ana Garcia","Laptop Pro")# otro ejemplo "Seguridad"defadmin_val(fucn):defwrapper(usuario,*args,**kwargs):if usuario.get("rol")=="admin":return fucn(usuario,*args,**kwargs)else:print("Acceso denegado. El usuario no es administrador.")return wrapper
@admin_valdefeliminar_producto(usuario, producto):print(f"El usuario {usuario['nombre']} ha eliminado el producto: {producto}")if __name__ =="__main__": usuario_admin ={"nombre":"Ana Garcia","rol":"admin"} usuario_normal ={"nombre":"Carlos Perez","rol":"usuario"} eliminar_producto(usuario_admin,"Laptop Pro") eliminar_producto(usuario_normal,"Laptop Pro")# Ejemplo "Aviso"defaviso_jefe(func):defwrapper(*args,**kwargs):print("Notificación: se ha hecho una venta")return func(*args,**kwargs)return wrapper
@aviso_jefedefprocesar_venta(nombre, producto):print(f"{nombre} está procesando la venta de: {producto}")if __name__ =="__main__": procesar_venta("Ana Garcia","Laptop Pro")
son los decoradores una forma de implementar polimorfismo en programacion funcional?
Que gran pregunta... Se parece pero no lo consideraría "polimorfismo", yo veo los decoradores como el principio "O" de los principios solid y el patrón de diseño decorador.
Reto:
from datetime import datetime
defcheck_access(func):defwrapper(employee):# Comprobar si el empleado tiene rol 'admin'if employee.get('role')=='admin':return func(employee)else:print('ACCESO DENEGADO. Solo los administradores pueden acceder.')return wrapper
defregister_date(func):defwrapper(employee): ahora = datetime.now()print(ahora) func(employee)if employee.get('role')==None:line =f"{ahora}: Acceso de {employee.get('name')}"else:line =f"{ahora}: Intento de acceso de {employee.get('name')}"try:withopen("registro_de_actividad.txt","a")asfile:file.write(f"\n{line}")except FileNotFoundError:withopen("registro_de_actividad.txt","w")asfile:file.write(line)return wrapper
@register_date@check_access#Aplica la funcion check acces como decorador de delete_employeedefdelete_employee(employee): employee["role"]=Noneprint(f'Elempleado {employee['name']} ha sido eliminado.')admin ={'name':'Carlos','role':'admin'}employee ={'name':'Ana','role':'employee'}delete_employee(admin)
Aunque no es lo mismo, esto me recordó un tema también importante que maneja ciclos de vida antes y después de ejecutar un proceso, y son los context manager, que se aseguran de manejar estados de inicio y de salida, se usa para liberar recursos o para acciones después de ejecutar un proceso. Vale la pena darle una mirada. :)
Me cosntó hasa que vi lo del @wraps:
from functools import wraps
defcheck_access(func):@wraps(func)# <--- TAMBÉ CAL AQUÍ!defwrapper(employee):# Comprobar si el empleado tiene rol 'admin'if employee.get('role')=='admin':return func(employee)else:print('ACCESO DENEGADO. Solo los administradores pueden acceder.')return wrapper
deflog_function(func):# cal posar la següent linia per evitar creuement de variables# entre docoradors@wraps(func)# <--- AIXÒ ÉS LA CLAU: copia la metadada de 'func' a 'wrapper'defwrapper(employee):withopen('log_user.txt',mode='a',encoding='utf-8')asfile: retorno = func(employee)file.write(f"\nEmpleado {employee['name']} ha ejecutado {func.__name__}")return retorno
return wrapper
@log_function@check_accessdefdelete_employee(employee):print(f'Elempleado {employee['name']} ha sido eliminado.')admin ={'name':'Carlos','role':'admin'}employee ={'name':'Ana','role':'employee'}#delete_employee(admin)delete_employee(employee)
from datetime import datetime
from functools import wraps
# =========================# DECORADOR PARA REGISTRAR ACCIONES# =========================defregistrar_accion(descripcion):defdecorador(func):@wraps(func)defenvoltura(*args,**kwargs): empleado = args[0]# self (objeto Empleado) fecha_hora = datetime.now().strftime("%Y-%m-%d %H:%M:%S")try:# Ejecutar la acción real resultado = func(*args,**kwargs)# Si todo sale bien, se registra como ÉXITO mensaje =(f"[{fecha_hora}] ÉXITO | "f"Empleado: {empleado.nombre} | "f"Cargo: {empleado.cargo} | "f"Acción: {descripcion}\n")return resultado
except Exception as e:# Si ocurre un error, también se registra mensaje =(f"[{fecha_hora}] ERROR | "f"Empleado: {empleado.nombre} | "f"Cargo: {empleado.cargo} | "f"Acción: {descripcion} | "f"Detalle: {str(e)}\n")raisefinally:# Guardar SIEMPRE en el archivo de textowithopen("registro_empleados.txt","a", encoding="utf-8")as archivo: archivo.write(mensaje)return envoltura
return decorador
# =========================# CLASE EMPLEADO# =========================classEmpleado:def__init__(self, nombre, cargo): self.nombre = nombre
self.cargo = cargo
self.inventario ={"Laptop Dell":5,"Laptop HP":3,"Laptop Lenovo":4} self.ventas =[]@registrar_accion("Inició sesión en el sistema")definiciar_sesion(self):print(f"\n✅ {self.nombre} ha iniciado sesión.\n")@registrar_accion("Consultó el inventario")defver_inventario(self):print("\n📦 INVENTARIO DISPONIBLE:")for producto, cantidad in self.inventario.items():print(f"- {producto}: {cantidad} unidades")print()@registrar_accion("Registró una venta")defregistrar_venta(self, producto, cantidad):if producto notin self.inventario:raise ValueError("El producto no existe en el inventario.")if cantidad <=0:raise ValueError("La cantidad debe ser mayor que cero.")if self.inventario[producto]< cantidad:raise ValueError("No hay suficiente stock disponible.")# Descontar del inventario self.inventario[producto]-= cantidad
# Guardar la venta self.ventas.append({"producto": producto,"cantidad": cantidad,"fecha": datetime.now().strftime("%Y-%m-%d %H:%M:%S")})print(f"\n💰 Venta registrada: {cantidad} unidad(es) de {producto}\n")@registrar_accion("Agregó stock al inventario")defagregar_stock(self, producto, cantidad):if cantidad <=0:raise ValueError("La cantidad debe ser mayor que cero.")if producto in self.inventario: self.inventario[producto]+= cantidad
else: self.inventario[producto]= cantidad
print(f"\n📥 Se agregaron {cantidad} unidad(es) de {producto} al inventario.\n")@registrar_accion("Consultó el historial de ventas")defver_ventas(self):print("\n🧾 HISTORIAL DE VENTAS:")ifnot self.ventas:print("No hay ventas registradas.\n")returnfor i, venta inenumerate(self.ventas, start=1):print(f"{i}. Producto: {venta['producto']} | Cantidad: {venta['cantidad']} | Fecha: {venta['fecha']}")print()@registrar_accion("Cerró sesión")defcerrar_sesion(self):print(f"\n🔒 {self.nombre} ha cerrado sesión.\n")# =========================# MENÚ INTERACTIVO# =========================defmenu():print("====================================")print(" SISTEMA DE GESTIÓN DE EMPLEADOS")print("====================================") nombre =input("Ingrese el nombre del empleado: ") cargo =input("Ingrese el cargo del empleado: ") empleado = Empleado(nombre, cargo)try: empleado.iniciar_sesion()except Exception as e:print(f"Error al iniciar sesión: {e}")whileTrue:print("========= MENÚ =========")print("1. Ver inventario")print("2. Registrar venta")print("3. Agregar stock")print("4. Ver historial de ventas")print("5. Cerrar sesión y salir")print("========================") opcion =input("Seleccione una opción: ")try:if opcion =="1": empleado.ver_inventario()elif opcion =="2": producto =input("Ingrese el nombre del producto: ") cantidad =int(input("Ingrese la cantidad vendida: ")) empleado.registrar_venta(producto, cantidad)elif opcion =="3": producto =input("Ingrese el nombre del producto: ") cantidad =int(input("Ingrese la cantidad a agregar: ")) empleado.agregar_stock(producto, cantidad)elif opcion =="4": empleado.ver_ventas()elif opcion =="5": empleado.cerrar_sesion()print("👋 Saliendo del sistema...")breakelse:print("⚠️ Opción no válida. Intente nuevamente.\n")except ValueError as ve:print(f"❌ Error: {ve}\n")except Exception as e:print(f"❌ Ocurrió un error inesperado: {e}\n")# =========================# PROGRAMA PRINCIPAL# =========================if __name__ =="__main__": menu()
"""
Implementar un nuevo decorador que registre cualquier acción realizada por un empleado enn un
nuevo archivo de texto
Aumentar decoradores para poder reutilizarlos
"""
# the function will check if the format is inPDFdef log_action(func): def wrapper(file):withopen('employee_actions.txt','a')asf: nombre = file['name'] formato = file['format'] f.write(f'Intento de subir archivo: {nombre} con formato {formato}\n')returnfunc(file)return wrapper
def check_format(func): def wrapper(file):if file.get('format')=='PDF':returnfunc(file)else:print('Formato incorrecto, solo se permite PDF')return wrapper
@log_action
@check_format
def upload_files(file):print(f'The file {file['name']} has been uploaded')file1 ={'name':'reporte_final','format':'PDF'}file2 ={'name':'base_de_datos','format':'csv'}print('---Intento 1 ---')upload_files(file1)print('---Intento 2 ---')upload_files(file2)
print(f"\n--- Resultados de auditoría para: {nombre_empleado} ---")
encontrado = False
try:
with open("auditoria.txt", "r", encoding="utf-8") as archivo:
for linea in archivo:
# Buscamos el nombre dentro de cada línea del archivo
if f"EMPLEADO: {nombre_empleado}" in linea:
print(linea.strip())
encontrado = True
if not encontrado:
print("No se encontraron registros para este empleado.")
except FileNotFoundError:
print("El archivo de auditoría aún no existe.")
# 3. aplicación en una clase
class GestionRRHH:
def __init__(self, empleado_nombre: str):
self.empleado_actual = empleado_nombre
@auditar_accion
def procesar_pago(self):
print("Procesando pago...")
@auditar_accion
def actualizar_datos(self):
print("Actualizando base de datos...")
# --- SISTEMA ---
# Simulamos acciones de un empleado
empleado_test = GestionRRHH("saul_Galvez")
empleado_test = GestionRRHH("stevan_Gutierez")
empleado_test.procesar_pago()
empleado_test.actualizar_datos()
# Consultamos lo que quedó registrado
consultar_auditoria("stevan_Gutierez" )
no se pero siento que ella usa muchas palabras rebuscadas o dificiles en su codigo, yo lo entendi mas asi con este codigo:
def decorador(funcion): def funcion_modificada():print("abriendo las puertas del local")funcion()print("cerrando las puertas del local")return funcion_modificada
@decorador
def trabajo():print("estoy trabajando")
Buenas! comparto una resolución del reto:
# implementar un decorador llamado log_employee_action que registre cualquier accion realizada por un empleado en un archivo de texto.
def log_employee_action(func): # decorador para registrar acciones de empleados
def wrapper(employee_name: str, action: str): # funcion wrapper que envuelve a la funcion original
# abre el archivo en modo append para no sobrescribir el contenido
with open("employee_actions.log", "a") as log_file: # open lo que hace es abrir un archivo, "a" es el modo append, log_file es el objeto archivo
log_file.write(f"Empleado: {employee_name}, Acción: {action}\n") # escribe en el archivo el nombre del empleado y la accion realizada
return func(employee_name, action) # llama a la funcion original con los argumentos proporcionados
return wrapper # retorna la funcion wrapper
@log_employee_action # aplica el decorador log_employee_action a la funcion perform_employee_action
def perform_employee_action(employee_name: str, action: str): # funcion que registra las acciones de los empleados
print(f"El empleado {employee_name} ha realizado la acción: {action}") # imprime en consola la accion realizada por el empleado
# Ejemplo de uso
if __name__ == "__main__": # bloque principal del programa, se ejecuta solo si el archivo es el programa principal, no si es importado como modulo
Creo que el objetico del ejemplo de la clase, era comprobar si el usuario tiene rol 'admin', para poder eliminar perfiles de empleados.
aquí dejo mi versión:
defcheck_access(func):defwrapper(user, employee):# Comprobar si el usuario tiene rol 'admin'if user.get('role')=='admin':return func(user, employee)else:print(f'{user['name']} ---> ACCES DENIED. Only admins can delete employees.')return wrapper
@check_accessdefdelete_employee(user, employee):print(f'Admin {user['name']} has deleted the employee {employee['name']}.')admin ={'name':'Andrés','role':'admin'}employee ={'name':'Salua','role':'employee'}# Posibles acciones delete_employee(admin, employee)delete_employee(admin, admin)delete_employee(employee, employee)delete_employee(employee, admin)
import datetime
from functools import wraps
# 📜 Decorador para registrar acciones de empleadosdeflog_employee_action(func):@wraps(func)# Preserva el nombre y docstring de la función originaldefwrapper(*args,**kwargs):# Suponemos que el primer argumento es el nombre del empleado empleado = args[0]if args else"Desconocido" accion = func.__name__
hora_actual = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")# Ejecutar la función original resultado = func(*args,**kwargs)# Registrar en el archivowithopen("log_empleados.txt","a", encoding="utf-8")as archivo: archivo.write(f"[{hora_actual}] Empleado: {empleado} - Acción: {accion}\n")print(f"📝 Acción registrada en log_empleados.txt: {empleado} -> {accion}")return resultado
return wrapper
# ----------------------------# Ejemplo de uso# ----------------------------@log_employee_actiondefiniciar_sesion(empleado:str):print(f"👤 {empleado} ha iniciado sesión.")@log_employee_actiondefrealizar_pedido(empleado:str, producto:str):print(f"🛍️ {empleado} realizó un pedido del producto: {producto}")@log_employee_actiondefcerrar_sesion(empleado:str):print(f"👋 {empleado} ha cerrado sesión.")# ----------------------------# Programa de ejemplo# ----------------------------if __name__ =="__main__": iniciar_sesion("Ana") realizar_pedido("Ana","Laptop") cerrar_sesion("Ana")
def salir_de_vacaciones(func): def wrapper(*args,**kwargs):print("📅 El empleado ha salido de vacaciones...") resultado =func(*args,**kwargs)print("✅ Acción registrada: empleado en vacaciones.")return resultado
return wrapper
@salir_de_vacaciones
def registrar_vacaciones(nombre):return f"{nombre} se encuentra en vacaciones."print(registrar_vacaciones({admin['name']}))