3 de noviembre de 2024
Evita Cálculos Repetitivos en Python usando cached_property
-
Blas Fernández
Supongamos que tenemos una clase que necesita realizar algunas operaciones, como cálculos o consultas a la base de datos, dentro de un atributo personalizado. Lo común sería elaborar algo similar a lo siguiente:
import time
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def information(self):
# Aquí realizamos operaciones costosas
result = self.calculate_complex_information()
return f"Name: {self.name}, Age: {self.age}, Info: {result}"
def calculate_complex_information(self):
# Simulamos un cálculo costoso o una consulta a la base de datos
time.sleep(2) # Simulamos un retraso de 2 segundos
return "Calculated information"
if __name__ == "__main__":
print("Starting...")
p = Person("John", 30)
# Tarda 2 segundos en mostrar la información
print(p.information)
# Tarda 2 segundos en mostrar la información
print(p.information)
Sin embargo, este enfoque tiene un problema: cada vez que accedemos al atributo information
, se realizarán nuevamente todas las operaciones costosas, lo cual puede ser ineficiente si accedemos a esta propiedad con frecuencia. Esto puede llevar a un rendimiento poco eficiente de nuestra aplicación, especialmente si la operación es particularmente lenta o si se accede a la propiedad múltiples veces.
Allí es donde puede ayudarnos la utilidad cached_property
que se encuentra disponible dentro de la librería estándar de Python desde la versión 3.8.
Esta utilidad nos permite almacenar en caché el resultado de una propiedad, evitando así cálculos repetitivos innecesarios. Funciona de manera similar a una propiedad regular, pero con la ventaja de que el valor se calcula solo una vez y se almacena para futuras llamadas. Veamos cómo podemos implementar esto en nuestro ejemplo anterior:
import time
from functools import cached_property
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
@cached_property
def information(self):
# Aquí realizamos operaciones costosas
result = self.calculate_complex_information()
return f"Name: {self.name}, Age: {self.age}, Info: {result}"
def calculate_complex_information(self):
# Simulamos un cálculo costoso o una consulta a la base de datos
time.sleep(2) # Simulamos un retraso de 2 segundos
return "Calculated information"
if __name__ == "__main__":
print("Starting...")
p = Person("John", 30)
# Tarda 2 segundos en mostrar la información la primera vez
print(p.information)
# Retorna inmediatamente sin importar la cantidad de llamadas que reciba
print(p.information)
print(p.information)
En este ejemplo modificado, hemos reemplazado el decorador @property
por @cached_property
. Ahora, cuando accedamos a la propiedad information
por primera vez, se realizará el cálculo costoso y se almacenará el resultado. En las siguientes llamadas, se devolverá el valor almacenado en caché sin necesidad de recalcular.