Clausuras en Python
Este post fue migrado de un blog hecho con Wordpress. Si se ve mal, dejame un comentario y lo arreglo.
Hace unos días leí este post en el blog de Javier Smaldone.
Closures: Essentially a closure is a block of code that can be passed as an argument to a function call.
Como parte de la didáctica Javier iba mostrando ejemplos que resolvía con algún lenguaje sin Clausuras (como Java o PHP) y con Ruby (el post trata sobre las Clausuras como una fortaleza de Ruby). Mientras leía fuí resolviendo los mismos ejemplos en Python y los dejé en forma de comentos. Como la identación no salió muy bien, los reproduzco aca:
Juanjo:
Las que siguen son soluciones en Python de los ejemplos que planteaste, algunas usan clausuras, otros puede que no :)
El ejemplo simple:
Supongamos que deseamos escribir una función que tome como parámetro un arreglo de valores enteros y retorne otro arreglo, producto de multiplicar por 2 cada uno de los elementos del parámetro.
def f(a): return [2*x for x in a]
El ejemplo de people:
Supongamos ahora que tenemos una clase "Person
", cuyo método "age
" calcula la edad de la persona. Si tenemos una colección de personas en el arreglo "people
" y deseamos obtener sólo aquellas que son mayores de 18 años.
[p.name for p in people if p.age > 18]
Problema 1:
Convertir las cadenas de un arreglo a mayúsculas.
a = [x.upper() for x in a]
Problema 2:
Dado un arreglo de la forma[["nombre", "apellido"]]
, obtener un arreglo de la forma["apellido, nombre"]
. Por ejemplo, dado:obtener:[["Javier","Smaldone"],["Santiago","Lobos"],["Bon","Scott"]]
["Smaldone, Javier", "Lobos, Santiago", "Scott, Bon"]
[”, “.join([y,x]) for [x,y] in a]
Problema 3:
Listar los nombres de las personas mayores de edad y mostrar la edad promedio de las mismas (según el ejemplo planteado anteriormente).
Este no quedó tan bien como los otros, pero te dejo mi interacción en REPL de Python:
>>> p1 = Persona() >>> p1.age = 19 >>> p1.name = “Juan Hewr” >>> p2 = Persona() >>> p2.age = 2 >>> p2.name = “Baby Jones” >>> p3 = Persona() >>> p3.age = 30 >>> p3.name = “Sussan Ahoria” >>> people = [p1, p2, p3] >>> s = 0.0 >>> adults = [p for p in people if p.age > 18] >>> for p in adults: print p.name s += p.age Juan Hewr Sussan Ahoria >>> print s/len(adults) 24.5
Problema 4:
Dado un arreglo de cadenas, obtener la de mayor longitud.
max(cadenas)
Javier:
Muchas gracias Juanjo por las soluciones.
Con respecto al problema 4, un detalle:
En Ruby también puedes obtener el máximo elemento de un arreglo ‘a’ usando
a.max
Sin embargo, la idea era mostrar como aplicar una función al estilo del ‘fold’ de los lenguajes funcionales. ¿Podrías reescribir la solución en esos términos?
Juanjo:
Primero una aclaración de algo que me pasé por alto: max(a) en Python cuando a es una lista de strings no da el string más largo sino el que está más al final en un ordenamiento creciente alfabético estando las minúsculas después que las mayúsculas. Es así también en ruby?
>>> max(”hola”, “juanjo”) ‘juanjo’ >>> max(”hola”, “Juanjo”) ‘hola’ >>> max(”a”, “A”) ‘a’ >>> max(”a”, “AAAAAAAAAAAAAAAAAAAAAa”) ‘a’ >>> max(”a”, “AAAAAAAAAAAAAAAAAAAAA”, “a”) ‘a’ >>> max(”AAAAAAAAAAAAAAAAAAAAA”, “a”) ‘a’ >>> max(”b”, “a”) ‘b’ >>> max(”B”, “a”) ‘a’
Javier:
Así es, Juanjo. Yo también me equivoqué. max, aplicado a strings devuelve el máximo según el orden lexicográfico, y no según la longitud.
Me sigue quedando la duda. ¿Hay algo similar a ‘inject’ o ‘fold’ en Python?
Juanjo:
Ahora si vamos a intentar resolver el ejemplo 4 en Python:
Mmm inject está bueno para resolver ese problema.. pero creo que no tenemos algo así en Python. Intentemos de todas formas:
Tenemos una lista de strings:
a = [”hola”, “juAnjO”, “Argentina”, “8″]
Una función ‘criterio’:
def longer(a, b): if len(a) > len(b): return a else: return b
And this magic functions called ‘mas’:
def mas(l, c, v): if l: return mas(l[1:], c, c(l[0], v)) else: return v
Que nos va a permitir hacer algo como esto:
>>> mas(a, longer, “”) ‘Argentina’
Mirando desde más cerca.. esta función ‘mas’, es muy parecida a ‘inject’, salvo por el nombre :)
>>> inject = mas >>> numeros = [1,2,3,4,5,6] >>> def suma(a, b): return a + b >>> inject(numeros, suma, 0) 21
Mmm parece que funciona, comprobemoslo:
>>> sum(numeros) 21
Si!
Nos leemos!
Comentarios
Comments powered by Disqus