Perlitas Python

Estas últimas semanas estuve bastante a full, especialmente con un montón de pequeñas cositas de Python, las tiro como popurrí...

El 28 de Agosto hubo un meetup en oficinas de Virtualmind (Socia Benefactora de la Asociación Civil. Fue el primero ahí y estuvo muy bueno, gracias Nariné por la coordinación por parte de la empresa y todo. Tuvimos las charlas de "Cómo publicar una biblioteca en PyPI (y todo lo que conlleva)" por Agustín Scaramuzza y "Testing basado en propiedades con Hypothesis" por Sasha, y después un espacio social mientras picábamos y tomábamos algo. Y después un grupito ya reducido nos fuimos un rato más por ahí...

El 30 de Agosto di mi ya clásica charla de Introducción a Python en el curso de posgrado Herramientas Computacionales para Científicos de la Universidad de La Plata. Esta vez como novedad invité a Yanina a que hable de la comunidad de Python y Python Argentina. Y después como siempre Manu y familia nos agasajaron en su casa (espectaculares pizzas caseras!).

Mañana viernes doy una charla, también de Intro a Python, en la Universidad Nacional de Hurlingham. Está bueno empezar a hacer cosas en Universidades, ojalá tuviera más tiempo para empujar esto más fuerte.

Este sábado, ya ya también, se realiza el PyDay de Rosario, al que lamentablemente no voy a poder asistir. Vayan que las charlas pintan buenísimas!!

Por suerte el 27 de Septiembre me desquito y voy (a Rosario, justamente) un meetup que hace rato estamos tratando de organizar en la sede de San Cristobal, que es Socia Benefactora de la Asociación Civil. Y tengo ganas de dar una charla ahí,. Así que si están por la zona y quieren pasar a saludar, bienvenides :) (especialmente si por algún motivo se pierden el PyDay de este sábado!!).

Charlas, charlas, charlas

Además de todo eso, muy a full con la PyConAr de Diciembre, preparando todo, coordinando a un grupo copado que están laburando un montón. En un par de días cierra el Call for Charlas, y ya estamos viendo el nuevo logo, vamos a hacer remeras (estén atentes a la preventa para comprarlas baratas!), ya tenemos confirmado a un keynote (nos falta una), y montón más de detallitos... o más bien, detallotes! :)

También, lo que me lleva bastante carga horaria (nos lleva, realmente, a Leandro (tesorero) y a mí), estoy ayudando al PyData Córdoba y el PyDay de Rosario recién mencionado, en esto de la Asociación Civil Python Argentina como paraguas de organización (básicamente, ayudar a la gente a hacer eventos, con cobertura institucional y manejo de dinero).

Y finalmente, a punto de terminar de renovar el logo de PyAr, ya tendremos novedades :D

Comentarios Imprimir

Series (y películas) a todo ritmo

Buena racha de ver pelis! Entre viajes, ratos libres, pelis que vi de casualidad, metí un montón estos últimos meses! Por otro lado, no anoté tantas nuevas para ver, así que ahí vamos bajando los pendientes.

En lo que también avancé bastante fue con las series...

  • Girls: bleh, pero me dió para terminarla; me gustó mucho la actuación de Adam Driver, un descubrimiento.
  • The Kaminsky Method: es MUY buena, especialmente si estás envejeciendo :p.
  • The Strain: una de vampiros, pero con una vuelta de tuerca "realista", muy explícito todo, Guillermo del Toro en su máxima expresión.
  • Louie: la corté, le dí cinco capítulos, pero es un humor que no me mueve un pelo. O sea, la comedia se basa en un humorista, sus monólogos, y vida, y lo que hace no me divierte. Seguro a otros le gustará.
  • Love, Death & Robots: la disfruté mucho. Hay algunos que bleh, pero como son cortitos, no pasa nada. Hay otros que son geniales.
  • The Bletchley Circle: está bien, bastante mejor la primer temporada que la segunda, pero son cortas así que zafa.

Ahora estoy con:

  • Vikings: promete, es larga, veremos como la llevan; por lo pronto me molesta la estúpida dicotomía de "violencia sí sexo no". O sea, está bien mostrar como a uno le cortan la cabeza y la sangre salpica todo, pero está mal mostrar una teta incluso al amamantar, ni hablemos de desnudos eróticos, o sexo!
  • True Detective: la primera temporada es MUY BUENA; creo haber escuchado que las otras dos no están relacionadas, ojalá no decaiga demasiado el nivel.
Carla Gugino en Gerald's Game

En fin, ¡películas!

  • A Scanner Darkly: -0. La historia está buena, tiene sus giros interesantes, pero se me hizo muy cuesta arriba el tipo de imagen (animada, todo el tiempo como "temblando").
  • Amateur: No la pude encontrar para ver :(.
  • Blind: +0. Una historia de amor, no mucho más, incluso un poco menos, pero está bien.
  • Bright: +0. Sobre-explicada, y con demasiados "rosas" en la historia, pero me gustó el acercamiento distinto a un tema clásico, y cómo maneja el "siempre hay un excluido".
  • Counterpart: Era una serie! La saqué de la lista de películas, entonces, la anoté en mi otra lista :)
  • Deadpool 2: +0. Entrega todo lo que promete, que no es demasiado: acción, humor negro, algunos chistes decentes, y no mucho más.
  • Distorted: -0. Tiene algunas partes interesantes, pero a nivel técnico / explicaciones, es todo demasiado "por encima", y constantes malas decisiones de les protagonistas aburre un poco. NO es un buen otro punto de vista sobre un tema ya trillado.
  • El faro de las orcas: +0. Muy linda película, los paisajes son imponentes, vale la pena incluso siendo tan leeenta.
  • Gerald's Game: +1. Me gustó mucho. Basada sobre un libro de Stephen King, el único libro en mi vida que lo tuve que cerrar en un momento porque me dio miedo (y estaba en el subte a las seis de la tarde). No recuerdo tanto la historia como para decir si fue bien llevada al cine, pero me gustó mucho como está hecha (la dificultad estructural de la conversión libro/peli reside en que la mitad de todo pasa estando una persona sola).
  • Infancia clandestina: +1. Muy buena, muy dura; vale la pena.
  • It: +1. Me gustó un montón, la peli asusta y tensiona, y aunque es un toque larga hay un montón de detalles de dirección y fotografía que la hacen super disfrutable. Falta la segunda mitad, claro.
  • Julie & Julia: +0. Una linda película sobre la historia de dos cocineras y sus pasiones.
  • La reina del miedo: -0. Me pareció entre sosa y tirada de los pelos.
  • Le vache: +0. Linda historia, interesante ver un tipo de vida al que no estamos acostumbrados, me gustaría verla visto en idioma original y subtitulada, la conseguí solamente doblada al castellano.
  • Los decentes: -1. Está bien expresada las diferencias de clase y la evolución de la piba en su descubrimiento. Pero es insoportablemente lenta. Hay una escena donde a una mujer se la ve por un pasillo y luego entra a la cocina, en el medio pasan 19 segundos de nada, de NADA. Es LENTA.
  • Marjorie Prime: -0. Está buena como uso experimental de una tecnología, pero es demasiado lenta, y un poco sin un "tema" o "sentido".
  • Mission: Impossible - Fallout: +0. Positivo si te gusta más o menos la saga. Me llamó la atención que me pareciera que las escenas de piñas/patadas/tiros no saturaban el resto de la película (por eso mi voto positivo), cuando eso es lo primero que me cansa. Una más de misión imposible, pero zafa.
  • Mother!: +1. Tiene una forma de llevarte por la historia MUY rara, pero efectiva, de transportarte por situaciones que no son sencillas de contar cinematográficamente. No tiene nada que ver, pero me dejó con ganas que ese director filme The Dark Tower como corresponde.
  • Replicas: -0. Demasiada fantasía y poca discusión sobre qué significa ser humano, "qué somos", etc. Keanu Reeves empieza a restarle a las películas, es el nuevo Nicolas Cage (?).
  • Solo: A Star Wars Story: +0. Está bien la historia en sí, se sostiene, la peli entretiene. Es una pochoclera más, pero mezclada con el resto de la historia, funciona.
  • Suburbicon: -0. La historia (aunque sorprende, tiene sus giros y te lleva) es bleh, y por un buen rato la película no va a ningún lado.
  • Surviving the 70's: +0. Excelentes las actuaciones de Alejandro Awada y Patricio Contreras, incluso Romina Ricci está a la altura. A la otra chica le falta un poco, pero no llega a restar. Muy "teatral", la historia está bien.
El coso

Más películas anotadas para ver:

  • Captain Marvel: (2019; Action, Adventure, Sci-Fi) Carol Danvers becomes one of the universe's most powerful heroes when Earth is caught in the middle of a galactic war between two alien races. [D: Anna Boden, Ryan Fleck; A: Brie Larson, Samuel L. Jackson, Ben Mendelsohn]
  • El cuento de las comadrejas: (2019; Comedy, Drama) A group of four old friends conformed by a film director, a film writer, an actress and her husband share a big house in the country. Their coexistence is menaced by a young couple who resourcefully and deceitfully seek to get them to sell the house to develop a real estate project of their own. [D: Juan José Campanella; A: Graciela Borges, Oscar Martínez, Luis Brandoni]
  • El increíble finde menguante: (2019; Drama) It's not a loop, it's a countdown: Alba is trapped in her weekend, forced to relive it over and over again, but each repetition gets a bit shorter. [D: Jon Mikel Caballero; A: Iria del Río, Adam Quintero, Nadia de Santiago]
  • La odisea de los giles: (2019; Adventure, Comedy, Crime, Drama, History, Thriller) Based on the book from Eduardo Sacheri "The Night of the Heroic Losers" (Alfaguara Novel Prize 2016). In a far-flung town in the province of Buenos Aires, many things are about to die out. During the economic crisis that led to the traumatic bank freeze of 2001, a group of men decides to gather the amount of money necessary to acquire some abandoned silos on an agro-industrial property. But even before they can carry out the project, a scam makes them hit rock bottom and react in the face of injustice. Now it's about robbing the thief. This novel narrates the story of a well-deserved collective revenge carried out during a legendary night that will never be forgotten.::chepevm [D: Sebastián Borensztein; A: Ricardo Darín, Luis Brandoni, Chino Darín]
  • Lucy in the Sky: (2019; Drama, Sci-Fi) Astronaut Lucy Cola returns to Earth after a transcendent experience during a mission to space, and begins to lose touch with reality in a world that now seems too small.::Fox Searchlight Pictures [D: Noah Hawley; A: Natalie Portman, Dan Stevens, Jon Hamm]
  • Empowered: (2018; Comedy) After to visit a Hindi guru healer, Paz loses control over what she says and starts speaking out everything that comes to her mind.::Chockys [D: Santiago Segura; A: Maribel Verdú, Diego Martín, Toni Acosta]
  • The Old Man & the Gun: (2018; Biography, Comedy, Crime, Drama, Romance) Based on the true story of Forrest Tucker and his audacious escape from San Quentin at the age of 70 to an unprecedented string of heists that confounded authorities and enchanted the public.::Fox Searchlight Pictures [D: David Lowery; A: Robert Redford, Casey Affleck, Sissy Spacek]
  • Yucatán: (2018; Comedy) Two white collar thieves compete fiercely against the other trying to steal millions from an old baker, that he won in the lotto.::Chockys [D: Daniel Monzón; A: Luis Tosar, Rodrigo De la Serna, Joan Pera]
  • Ad Astra: (2019; Adventure, Drama, Mystery, Sci-Fi, Thriller) An astronaut travels to the outer edges of the solar system to find his father and unravel a mystery that threatens the survival of our planet. He uncovers secrets which challenge the nature of human existence and our place in the cosmos. [D: James Gray; A: Brad Pitt, Liv Tyler, Ruth Negga]
  • Terminator: Dark Fate: (2019; Action, Adventure, Sci-Fi) Sarah Connor has returned from far away, and she's gearing up with a team of agents who will fight against T-1000. [D: Tim Miller; A: Arnold Schwarzenegger, Edward Furlong, Mackenzie Davis]
El escenario de Mother

Finalmente, el conteo de pendientes por fecha:

(Dic-2013)    4
(Abr-2014)    3
(Jul-2014)   10   5   1
(Nov-2014)   22  22   7
(Feb-2015)   13  13  10
(Jun-2015)   16  15  13  11   1
(Dic-2015)   21  19  19  18   6   1
(May-2016)       26  25  23  21   9
(Sep-2016)           19  19  18  14   1
(Feb-2017)               26  25  23  21   9   1
(Jun-2017)                   23  23  21  18   5
(Dic-2017)                       19  19  18  16   5
(May-2018)                           22  22  22  17
(Sep-2018)                               12  12  12
(Mar-2019)                                   13  13
(Ago-2019)                                       10
Total:       89 100  94  97  94  89  84  79  69  57
Comentarios Imprimir

Complejidad, performance, y expresiones regulares

Hace algunos meses (sí, este post me había quedado en el tintero) se presentó en el laburo una tarea particular: había que evitar algunas búsquedas que se estaban haciendo en el Snap Store que no tenían realmente sentido (y algunas complicaban al buscador), como por ejemplo 123333333333333333333. En estos casos es útil contestar "vacío" directamente sin hacer laburar al sistema.

Cuando me comentaron del inconveniente me ofrecí a agarrar la tarea, porque ya había hecho esto mismo. Es más, hice un poco de arqueología y encontré un código muy similar, que en su momento había escrito para el buscador de scopes. Entre otras restricciones a las búsquedas, estaba la de "detectar ráfagas de letras iguales".

O sea que si en una búsqueda cualquier letra se repetía más de N veces sin otra cosa en el medio, esa búsqueda no tiene sentido. Como ejemplo, para N=3 la búsqueda foxxbarxxxdox es correcta, pero monroooose no. En el primer caso no importa que la x aparezca muchas veces, nunca aparece ininterrumpidamente más que 3, y en el segundo caso la o aparece en una ráfaga de 4 veces: alpiste.

Buscar palabras en servicios web es más sencillo que buscar el destino (?)

El código que rescaté (y usé en el nuevo servicio) era exactamente este:

# detect a "lot of same letter in a row"
cnt = 1
prev = None
for char in term:
    if char == prev:
        cnt += 1
        if cnt > MAX_REPEATED_IN_A_ROW:
            return True
    else:
        cnt = 1
        prev = char

La variable term es justamente la palabra buscada, y MAX_REPEATED_IN_A_ROW es una constante del módulo que indica el N que hablábamos arriba (pero mejor descripto, je).

Cuando propuse el branch, la persona que hizo el review le pareció que se podía mejorar ese algoritmo. O mejor dicho, reemplazarlo totalmente por una expresión regular, y propuso lo siguiente:

for char in term:
    if re.search(r"{char}{times,}".format(char=char, times=MAX_REPEATED_IN_A_ROW), term):
        return True

Casi enseguida, se dio cuenta que hacer una regex (apócope en inglés para "expresión regular") por cada caracter no iba a estar bueno, y mejoró (?) la misma para hacer solamente una regex en total:

if re.search(r"(\w)\1{{{times},}}".format(times=MAX_REPEATED_IN_A_ROW - 1), term):
    return True

¿Valía la pena ir a algo más complejo? ¿O no era tanto más complejo? El loop original no me gustaba del todo, realmente, pero me parecía más fácil de entender que una expresión regular como las propuestas... y también más sencilla de modificar a futuro si los requerimientos cambiaban sutilmente.

Por otro lado, las expresiones regulares parecían funcionar en las pruebas que había realizado a mano (y en los test cases que tenía. Y quizás fuese más rápido, después de todo estamos cambiando un algoritmo hecho en Python por una regex (cuyo motor está hecho en C). Pero no me convencía hacer el cambio.

Para agregar elementos en el análisis, me propuse medir tiempos. La mejor forma era simular la realidad, así que pedí los logs de alguno de los servidores, agarre toneladas de búsquedas reales de un par de semanas anteriores (176 mil), y me puse a medir cuanto tardaba tanto el loop original como las dos regexes propuestas como reemplazo (todos pensábamos que la segunda era más rápida que la primera, pero no costaba nada comprobarlo).

Al comenzar este análisis encontré rápidamente que la regex "lenta" no servía del todo: explotaba por el aire con búsquedas como ter$. La descarté para hacer foco en los otros dos códigos y no irme por las ramas.

Ya desconfiando, armé un programita que no sólo analice los tiempos del loop y la regex rápida, sino que también compare los resultados... y vi que no daban lo mismo siempre! Exploré un poquito y encontré que la regex "rápida" daba resultados erróneos para búsquedas como loch,,,,,,,,,,.

Mejoramos entonces la regex, y nos quedó:

if re.search(r"(\.)\1{{{times},}}".format(times=MAX_REPEATED_IN_A_ROW - 1), term):
   return True

Esta funcionó, al menos para todos los ejemplos que yo tenía para medir los tiempos. Pero cuanto podía confiar que no íbamos a encontrar otro caso en el futuro que la haga romper?

¿Y si yo no hacía correr todos los ejemplos y metíamos la anterior, que no funcionaba del todo?

Hay una frase en modo de chiste (pero más o menos verdad) que dice que "si tenés un problema, y para resolverlo usás expresiones regulares, ahora tenés dos problemas".

Por otro lado, ¿valía la pena el cambio a nivel de velocidad?

Pongámonos a medir tiempos, pasame el cronómetro

Los resultados del análisis de tiempos me terminó dando que la última expresión regular tardaba (en promedio, para cada búsqueda) 1.5056µs, mientras que el loop tardaba 1.456µs.

La regex era más lenta, por casi 50 nanosegundos.

Dejé el loop.

Comentarios Imprimir