UNIDAD IV
Programación Funcional
Lenguajes de Programación
Ingeniería en Computación e Informática
Semestre 2019-1
Generadores y decoradores
Generadores
¿Que son los Generadores?
Son una clase especial de funciones que no generan una lista, sino una secuencia de valores sobre el que iterar.
Pueden ser:
- Métodos generadores: incluyen la palabra “yield” y se declaran como funciones
- Expresión generadora: se declara como listas por comprensión entre “()”
¿Para qué sirven los generadores?
- Para generar secuencias en tiempo de ejecución.
- Acelerar búsquedas y crear bucles más rápidos.
- Mejorar la legibilidad de nuestro código
¿Cómo se construyen los generadores?
- Para construir generadores sólo tenemos que usar la orden yield.
- Esta orden devolverá un valor y además congelará la ejecución de la función hasta la próxima vez que le pidamos un valor.
Ejemplos (i)
def gen_basico():
yield "uno"
yield "dos"
yield "tres"
if __name__ == '__main__':
# un bucle
for g in gen_basico():
print(g)
# convertir la generacion en una lista
print(list(g))
# ejecutar con python3
#~ python gen_1.py
Ejemplos (ii)
def pares():
index = 1
# En este caso definimos un bucle infinito
while True:
# Devolvemos un valor
yield index*2
index = index + 1
if __name__ == '__main__':
# un bucle
for par in pares():
print(par)
# cortamos el bucle para ejemplificar
if par >= 50:
break
# ejecutar con python3
#~ python gen_2.py
Ejemplos (iii)
def multiplos_de(n):
index = 1
while True:
yield index*n
index = index + 1
if __name__ == '__main__':
# un bucle
for multiplo in multiplos_de(3):
print(multiplo)
# cortamos el bucle para ejemplificar
if multiplo >= 30:
break
# ejecutar con python3
#~ python gen_3.py
Ejemplos (iv)
import random
def generador_ips(cantidad):
for i in range(cantidad):
a = random.randint(0,255)
b = random.randint(0,255)
c = random.randint(0,255)
d = random.randint(0,255)
yield '{0}.{1}.{2}.{3}' . format(a,b,c,d)
if __name__ == '__main__':
# generar 5 ips
ips = generador_ips(5)
print(list(ips))
# ejecutar con python3
#~ python gen_4.py
Ejercicios en clases
Ejercicio 1
Implementa un generador sucesos (probabilidad) que produce una secuencia infinita de valores booleanos pseudoaletoreos con probabilidad de que sean True. es decir, retornar true si el valor aleatorio es menor a 0.5 y false en caso contrario.
Hint: Utiliza la función random.random () para generar un número pseudo-aleatoreo entre 0.0 y 1.0.
Ejercicios en clases
Ejercicio 2
Implementa un generador de números primos que funcione de la siguiente forma:
for primo in generador_primos(10): print primo
Ejercicios en clases
Ejercicio 3
Implementa un generador fibonacci que produce los diferentes de la secuencia de Fibonacci, que tiene la forma:
0, 1, 1, 2, 3, 5, 8, 13, ...
Cuyos dos primeros valores son 0 y 1 por definición y el resto se calculan sumando los dos últimos valores de la sucesión.
Decoradores
¿Que son los decoradores?
- Son funciones que reciben una función como parámetro y devuelve otra función.
- Cambian el comportamiento de un función, método o clase sin modificar su código.
- Crea un “envoltura” alrededor de la función a decorar, esta envoltura y la función original son la nueva función que obtenemos.
Ejemplos
def mi_decorador(funcion):
def nueva(*args):
print("Llamada a la funcion", funcion.__name__)
retorno = funcion(*args)
return retorno
return nueva
@mi_decorador
def mi_fn():
print(" Hola Mundo ")
if __name__ == '__main__':
mi_fn()
Patron Memoize
- El término "memoization" o "memoize" fue introducido por Donald Michie en el año 1968
- El patrón es una técnica utilizada en la computación para acelerar los programas
- El patrón memoize consiste en almacenar las soluciones calculadas previamente, para evitar que sean recalculadas, con lo anterior se reduce el tiempo computacional de nuestros algoritmos.
- El patrón "memoize" puede ser programada explícitamente por el desarrollador, pero algunos lenguajes de programación como Python proporcionan mecanismos para memorizar automáticamente las funciones (decoradores).
Ejemplo: función fibonacci sin memoize
# Función fibonacci recursiva
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
f = fibonacci(6)
Ejemplo: árbol de calculo
En el árbol de ejecución se producen situaciones donde se realiza el cálculo de algún valor n veces.
Ejemplo: Patrón Memoize
def memoize(f):
memory = {}
def wrapper(n):
if n not in memory:
memory[n] = f(n)
return memory[n]
return wrapper
Ejemplo: Fibonacci con patrón Memoize
def memoize(f):
memory = {}
def wrapper(n):
if n not in memory:
memory[n] = f(n)
return memory[n]
return wrapper
# Utilizando Memoize
@memoize
def fib_memoize(n):
if n < 2:
return n
return fib_memoize(n - 1) + fib_memoize(n - 2)
if __name__ == '__main__':
fib_memoize(6)
Ejemplo: Fibonacci con patrón Memoize
- Se utiliza el decorador construido para utilizar fibonacci con memoización
- El patrón a través de los decoradores puede ser aplicado a cualquier función o método de tu proyecto
Actividad en clases
- Construya una función que permita calcular n! de forma recursiva. Aplique la memoización en su ejecución.
Solución
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def memoize(f):
memory = {}
def wrapper(n):
if n not in memory:
memory[n] = f(n)
return memory[n]
return wrapper
@memoize
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
if __name__ == '__main__':
fact = factorial(5)
print(fact)
Recursos
- https://github.com/mcantillana/generadores_decoradores
- https://www.python-course.eu/python3_memoization.php
- http://nereida.deioc.ull.es/~lpp/perlexamples/node170.html
Decoradores y Generadores
By Miguel Cantillana
Decoradores y Generadores
Lab 5
- 602