Saltar al contenido

Evaluación perezosa en Python

Recuerda que en la informática un problema casi siempere puede tener diferentes resoluciones, no obstante nosotros aquí mostraremos lo mejor y más eficiente.

Solución:

El objeto devuelto por range() (o xrange() en Python2.x) se conoce como iterable perezoso.

En lugar de almacenar todo el rango, [0,1,2,..,9]en la memoria, el generador almacena una definición para (i=0; i<10; i+=1) y calcula el siguiente valor solo cuando es necesario (también conocido como evaluación perezosa).

Esencialmente, un generador le permite devolver una estructura similar a una lista, pero aquí hay algunas diferencias:

  1. Una lista almacena todos los elementos cuando se crea. Un generador genera el siguiente elemento cuando se necesita.
  2. Se puede iterar una lista tanto como sea necesario, un generador solo se puede iterar sobre exactamente una vez.
  3. Una lista puede obtener elementos por índice, un generador no puede; solo genera valores una vez, de principio a fin.

Un generador se puede crear de dos maneras:

(1) Muy similar a una lista de comprensión:

# this is a list, create all 5000000 x/2 values immediately, uses []
lis = [x/2 for x in range(5000000)]

# this is a generator, creates each x/2 value only when it is needed, uses ()
gen = (x/2 for x in range(5000000)) 

(2) Como una función, usando yield para devolver el siguiente valor:

# this is also a generator, it will run until a yield occurs, and return that result.
# on the next call it picks up where it left off and continues until a yield occurs...
def divby2(n):
    num = 0
    while num < n:
        yield num/2
        num += 1

# same as (x/2 for x in range(5000000))
print divby2(5000000)

Nota: A pesar de range(5000000) es un generador en Python3.x, [x/2 for x in range(5000000)] sigue siendo una lista. range(...) hace su trabajo y genera x uno a la vez, pero la lista completa de x/2 los valores se calcularán cuando se cree esta lista.

En pocas palabras, la evaluación perezosa significa que el objeto se evalúa cuando se necesita, no cuando se crea.

En Python 2, el rango devolverá una lista; esto significa que si le da un número grande, calculará el rango y lo devolverá en el momento de la creación:

>>> i = range(100)
>>> type(i)

En Python 3, sin embargo, obtienes un objeto de rango especial:

>>> i = range(100)
>>> type(i)

Solo cuando lo consuma, se evaluará realmente; en otras palabras, solo devolverá los números en el rango cuando realmente los necesite.

Un repositorio de github llamado patrones de python y wikipedia nos dicen qué es la evaluación perezosa.

Retrasa la evaluación de una expresión hasta que se necesita su valor y evita evaluaciones repetidas.

range en python3 no es una evaluación perezosa completa, porque no evita la evaluación repetida.

Un ejemplo más clásico de evaluación perezosa es cached_property:

import functools

class cached_property(object):
    def __init__(self, function):
        self.function = function
        functools.update_wrapper(self, function)

    def __get__(self, obj, type_):
        if obj is None:
            return self
        val = self.function(obj)
        obj.__dict__[self.function.__name__] = val
        return val

Cached_property (también conocido como lazy_property) es un decorador que convierte una función en una propiedad de evaluación perezosa. La primera vez que se accede a la propiedad, se llama a la función para obtener el resultado y luego se usa el valor la próxima vez que acceda a la propiedad.

p.ej:

class LogHandler:
    def __init__(self, file_path):
        self.file_path = file_path

    @cached_property
    def load_log_file(self):
        with open(self.file_path) as f:
            # the file is to big that I have to cost 2s to read all file
            return f.read()

log_handler = LogHandler('./sys.log')
# only the first time call will cost 2s.
print(log_handler.load_log_file)
# return value is cached to the log_handler obj.
print(log_handler.load_log_file)

Para usar una palabra adecuada, un objeto generador de python como distancia son más como diseñados a través de llamar_por_necesidad patrón, en lugar de evaluación perezosa

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *