Guillermo Vayá <guivaya@gmail.com>
Twitter: @Willyfrog_
Github: Willyfrog
Trabajo en:
Funciones de Orden Superior: funciones=valor
Nos lleva a: Lambdas y Closures
from nose.tools import raises @raises(Exception) def test_that_fails_by_passing(): pass
Composicion de dos funciones
def compose_fn(f1, f2): return lambda x: f1(f2(x))
asegura_impar = compose_fn( lambda x: x +1, lambda x: x * 2 )
Y a partir de aquí, seguimos…
compose_fn(compose_fn(compose_fn(.......)))
Dos ejecuciones de la misma función no generan el mismo resultado.
Tratar de acotarlo
def hola(nombre): escribe_a_fichero("hola {0}".format(nombre)) return cuenta_lineas()
En python mejor no preocuparse por ella…
… pero intentar minimizar!
tuplas y tuplas con nombre
no son tan flexibles como la lista y el diccionario.
menor consumo de memoria
estructuras mas simples
Usamos variaciones de ellas a menudo, posiblemente imperativas (loops)
Díficil comprension inicial, pero después generan código limpio y claro
Estan presentes en casi todos los lenguajes desde hace tiempo (excepción: Go)
[item * 2 for item in item_list if (x % 2)]
Agrupa los resultados de una secuencia mediante una funcion
No reproducible mediante list comprehensions
usar functools.reduce
en Python3
reduce(lambda acc, x: acc + [x*2] if (x % 2) else acc, range(1,5), [])
def reducir(funcion, secuencia, inicial=None): if not secuencia: return inicial acc = inicial while secuencia: valor = secuencia.pop() acc = funcion(acc, valor) return acc
def reducir(funcion, secuencia, inicial=None): if not secuencia: return inicial valor = secuencia.pop() return reducir(funcion, secuencia, funcion(valor, inicial))
En python no es cómodo: nos falta pattern matching
Deja una lista con los valores que nos interesan
def filtrar(filtro, secuencia): parcial = anade_si(filtro) return reducir(parcial, secuencia, []) def anade_si(filtro): return lambda acc, valor: [valor] + acc if filtro(valor) else acc
Recorre una lista
def mapear(funcion, secuencia): parcial = aplica_une(funcion) return reducir(parcial, secuencia, []) def aplica_une(funcion): return lambda acc, valor: [funcion(valor)] + acc
[map for secuencia if filter]
print mapear( lambda x: x * 2, filtrar(lambda y: y % 2, range(1, 5)) )
x2 = lambda x: x * 2 impar = lambda y: y % 2 print mapear( x2, filtrar(impar, range(1, 5)) )
filtra_impares = lambda r: filtrar(impar, r) print mapear(x2, filtra_impares(range(1, 5))) dobla_impares = lambda sec: mapear(x2, filtra_impares(sec)) print dobla_impares(range(1, 5))
def cuenta(num): return cuenta(num-1) if num > 0 else "This is the end" print cuenta(1000000)
Traceback (most recent call last): File "ejemplos.py", line 30, in <module> print cuenta(1000000) File "ejemplos.py", line 22, in cuenta return cuenta(num-1) if num > 0 else "This is the end"
…(cerca de 1000 repeticiones de la mista aburrida traza)
File "ejemplos.py", line 22, in cuenta return cuenta(num-1) if num > 0 else "This is the end" RuntimeError: maximum recursion depth exceeded
import sys
sys.setrecursionlimit(1000001)
TCO elimina el stack de la recursividad
una llamada es recursiva usando tailcall si al final de la ejecucion solo queda una llamada a la funcion
def suma(secuencia): """No TailCall""" if not secuencia: return 0 x = pop(secuencia) return x + suma(secuencia)
def suma(secuencia): """TailCall""" return _suma(secuencia, 0) def _suma(secuencia, acc): if not secuencia: return acc x = secuencia.pop() return _suma(secuencia, acc+x)
Usar un bucle que llame a la funcion que queremos hacer recursiva con un centinela para que avise de cuando dejar de invocarla
def trampolin(fun, *args, **kwargs): result = [fun, args, kwargs] while es_funcion(result): (fn, fun_args) = (result[0], result[1]) if (len(result) == 3): fun_kwargs = result[2] else: fun_kwargs = {} result = fn(*fun_args, **fun_kwargs) return result def es_funcion(lista): try: return callable(lista[0]) except: return False
def cuenta_t(num): return [cuenta_t, [num-1]] if num > 0 else "This is the end" print trampolin(cuenta_t, 1000000)
>>> from ejemplos import *
>>> print trampolin(cuentat, 1000000)
This is the end
https://docs.python.org/2/library/functools.html
Utilidades funcionales
https://github.com/kachayev/fn.py
Lisp compatible con python
Ampliar tu forma de pensar
¿Preguntas?
Guillermo Vayá <guivaya@gmail.com>
Twitter: @Willyfrog_
Github: Willyfrog
Trabajo en:
No uses este codigo